1 | /* ----------------------------------------------------------------------- * |
2 | * |
3 | * Copyright 1996-2018 The NASM Authors - All Rights Reserved |
4 | * See the file AUTHORS included with the NASM distribution for |
5 | * the specific copyright holders. |
6 | * |
7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following |
9 | * conditions are met: |
10 | * |
11 | * * Redistributions of source code must retain the above copyright |
12 | * notice, this list of conditions and the following disclaimer. |
13 | * * Redistributions in binary form must reproduce the above |
14 | * copyright notice, this list of conditions and the following |
15 | * disclaimer in the documentation and/or other materials provided |
16 | * with the distribution. |
17 | * |
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
19 | * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |
20 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
22 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
23 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
24 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
25 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
26 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
29 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, |
30 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
31 | * |
32 | * ----------------------------------------------------------------------- */ |
33 | |
34 | /* |
35 | * eval.c expression evaluator for the Netwide Assembler |
36 | */ |
37 | |
38 | #include "compiler.h" |
39 | |
40 | #include <stdio.h> |
41 | #include <stdlib.h> |
42 | #include <stddef.h> |
43 | #include <string.h> |
44 | #include <ctype.h> |
45 | |
46 | #include "nasm.h" |
47 | #include "nasmlib.h" |
48 | #include "ilog2.h" |
49 | #include "error.h" |
50 | #include "eval.h" |
51 | #include "labels.h" |
52 | #include "float.h" |
53 | #include "assemble.h" |
54 | |
55 | #define TEMPEXPRS_DELTA 128 |
56 | #define TEMPEXPR_DELTA 8 |
57 | |
58 | static scanner scan; /* Address of scanner routine */ |
59 | |
60 | static expr **tempexprs = NULL; |
61 | static int ntempexprs; |
62 | static int tempexprs_size = 0; |
63 | |
64 | static expr *tempexpr; |
65 | static int ntempexpr; |
66 | static int tempexpr_size; |
67 | |
68 | static struct tokenval *tokval; /* The current token */ |
69 | static int i; /* The t_type of tokval */ |
70 | |
71 | static void *scpriv; |
72 | static int *opflags; |
73 | |
74 | static struct eval_hints *hint; |
75 | static int64_t deadman; |
76 | |
77 | |
78 | /* |
79 | * Unimportant cleanup is done to avoid confusing people who are trying |
80 | * to debug real memory leaks |
81 | */ |
82 | void eval_cleanup(void) |
83 | { |
84 | while (ntempexprs) |
85 | nasm_free(tempexprs[--ntempexprs]); |
86 | nasm_free(tempexprs); |
87 | } |
88 | |
89 | /* |
90 | * Construct a temporary expression. |
91 | */ |
92 | static void begintemp(void) |
93 | { |
94 | tempexpr = NULL; |
95 | tempexpr_size = ntempexpr = 0; |
96 | } |
97 | |
98 | static void addtotemp(int32_t type, int64_t value) |
99 | { |
100 | while (ntempexpr >= tempexpr_size) { |
101 | tempexpr_size += TEMPEXPR_DELTA; |
102 | tempexpr = nasm_realloc(tempexpr, |
103 | tempexpr_size * sizeof(*tempexpr)); |
104 | } |
105 | tempexpr[ntempexpr].type = type; |
106 | tempexpr[ntempexpr++].value = value; |
107 | } |
108 | |
109 | static expr *finishtemp(void) |
110 | { |
111 | addtotemp(0L, 0L); /* terminate */ |
112 | while (ntempexprs >= tempexprs_size) { |
113 | tempexprs_size += TEMPEXPRS_DELTA; |
114 | tempexprs = nasm_realloc(tempexprs, |
115 | tempexprs_size * sizeof(*tempexprs)); |
116 | } |
117 | return tempexprs[ntempexprs++] = tempexpr; |
118 | } |
119 | |
120 | /* |
121 | * Add two vector datatypes. We have some bizarre behaviour on far- |
122 | * absolute segment types: we preserve them during addition _only_ |
123 | * if one of the segments is a truly pure scalar. |
124 | */ |
125 | static expr *add_vectors(expr * p, expr * q) |
126 | { |
127 | int preserve; |
128 | |
129 | preserve = is_really_simple(p) || is_really_simple(q); |
130 | |
131 | begintemp(); |
132 | |
133 | while (p->type && q->type && |
134 | p->type < EXPR_SEGBASE + SEG_ABS && |
135 | q->type < EXPR_SEGBASE + SEG_ABS) { |
136 | int lasttype; |
137 | |
138 | if (p->type > q->type) { |
139 | addtotemp(q->type, q->value); |
140 | lasttype = q++->type; |
141 | } else if (p->type < q->type) { |
142 | addtotemp(p->type, p->value); |
143 | lasttype = p++->type; |
144 | } else { /* *p and *q have same type */ |
145 | int64_t sum = p->value + q->value; |
146 | if (sum) { |
147 | addtotemp(p->type, sum); |
148 | if (hint) |
149 | hint->type = EAH_SUMMED; |
150 | } |
151 | lasttype = p->type; |
152 | p++, q++; |
153 | } |
154 | if (lasttype == EXPR_UNKNOWN) { |
155 | return finishtemp(); |
156 | } |
157 | } |
158 | while (p->type && (preserve || p->type < EXPR_SEGBASE + SEG_ABS)) { |
159 | addtotemp(p->type, p->value); |
160 | p++; |
161 | } |
162 | while (q->type && (preserve || q->type < EXPR_SEGBASE + SEG_ABS)) { |
163 | addtotemp(q->type, q->value); |
164 | q++; |
165 | } |
166 | |
167 | return finishtemp(); |
168 | } |
169 | |
170 | /* |
171 | * Multiply a vector by a scalar. Strip far-absolute segment part |
172 | * if present. |
173 | * |
174 | * Explicit treatment of UNKNOWN is not required in this routine, |
175 | * since it will silently do the Right Thing anyway. |
176 | * |
177 | * If `affect_hints' is set, we also change the hint type to |
178 | * NOTBASE if a MAKEBASE hint points at a register being |
179 | * multiplied. This allows [eax*1+ebx] to hint EBX rather than EAX |
180 | * as the base register. |
181 | */ |
182 | static expr *scalar_mult(expr * vect, int64_t scalar, int affect_hints) |
183 | { |
184 | expr *p = vect; |
185 | |
186 | while (p->type && p->type < EXPR_SEGBASE + SEG_ABS) { |
187 | p->value = scalar * (p->value); |
188 | if (hint && hint->type == EAH_MAKEBASE && |
189 | p->type == hint->base && affect_hints) |
190 | hint->type = EAH_NOTBASE; |
191 | p++; |
192 | } |
193 | p->type = 0; |
194 | |
195 | return vect; |
196 | } |
197 | |
198 | static expr *scalarvect(int64_t scalar) |
199 | { |
200 | begintemp(); |
201 | addtotemp(EXPR_SIMPLE, scalar); |
202 | return finishtemp(); |
203 | } |
204 | |
205 | static expr *unknown_expr(void) |
206 | { |
207 | begintemp(); |
208 | addtotemp(EXPR_UNKNOWN, 1L); |
209 | return finishtemp(); |
210 | } |
211 | |
212 | /* |
213 | * The SEG operator: calculate the segment part of a relocatable |
214 | * value. Return NULL, as usual, if an error occurs. Report the |
215 | * error too. |
216 | */ |
217 | static expr *segment_part(expr * e) |
218 | { |
219 | int32_t seg; |
220 | |
221 | if (is_unknown(e)) |
222 | return unknown_expr(); |
223 | |
224 | if (!is_reloc(e)) { |
225 | nasm_error(ERR_NONFATAL, "cannot apply SEG to a non-relocatable value" ); |
226 | return NULL; |
227 | } |
228 | |
229 | seg = reloc_seg(e); |
230 | if (seg == NO_SEG) { |
231 | nasm_error(ERR_NONFATAL, "cannot apply SEG to a non-relocatable value" ); |
232 | return NULL; |
233 | } else if (seg & SEG_ABS) { |
234 | return scalarvect(seg & ~SEG_ABS); |
235 | } else if (seg & 1) { |
236 | nasm_error(ERR_NONFATAL, "SEG applied to something which" |
237 | " is already a segment base" ); |
238 | return NULL; |
239 | } else { |
240 | int32_t base = ofmt->segbase(seg + 1); |
241 | |
242 | begintemp(); |
243 | addtotemp((base == NO_SEG ? EXPR_UNKNOWN : EXPR_SEGBASE + base), |
244 | 1L); |
245 | return finishtemp(); |
246 | } |
247 | } |
248 | |
249 | /* |
250 | * Recursive-descent parser. Called with a single boolean operand, |
251 | * which is true if the evaluation is critical (i.e. unresolved |
252 | * symbols are an error condition). Must update the global `i' to |
253 | * reflect the token after the parsed string. May return NULL. |
254 | * |
255 | * evaluate() should report its own errors: on return it is assumed |
256 | * that if NULL has been returned, the error has already been |
257 | * reported. |
258 | */ |
259 | |
260 | /* |
261 | * Grammar parsed is: |
262 | * |
263 | * expr : bexpr [ WRT expr6 ] |
264 | * bexpr : rexp0 or expr0 depending on relative-mode setting |
265 | * rexp0 : rexp1 [ {||} rexp1...] |
266 | * rexp1 : rexp2 [ {^^} rexp2...] |
267 | * rexp2 : rexp3 [ {&&} rexp3...] |
268 | * rexp3 : expr0 [ {=,==,<>,!=,<,>,<=,>=} expr0 ] |
269 | * expr0 : expr1 [ {|} expr1...] |
270 | * expr1 : expr2 [ {^} expr2...] |
271 | * expr2 : expr3 [ {&} expr3...] |
272 | * expr3 : expr4 [ {<<,>>} expr4...] |
273 | * expr4 : expr5 [ {+,-} expr5...] |
274 | * expr5 : expr6 [ {*,/,%,//,%%} expr6...] |
275 | * expr6 : { ~,+,-,IFUNC,SEG } expr6 |
276 | * | (bexpr) |
277 | * | symbol |
278 | * | $ |
279 | * | number |
280 | */ |
281 | |
282 | static expr *rexp0(int), *rexp1(int), *rexp2(int), *rexp3(int); |
283 | |
284 | static expr *expr0(int), *expr1(int), *expr2(int), *expr3(int); |
285 | static expr *expr4(int), *expr5(int), *expr6(int); |
286 | |
287 | static expr *(*bexpr) (int); |
288 | |
289 | static expr *rexp0(int critical) |
290 | { |
291 | expr *e, *f; |
292 | |
293 | e = rexp1(critical); |
294 | if (!e) |
295 | return NULL; |
296 | |
297 | while (i == TOKEN_DBL_OR) { |
298 | i = scan(scpriv, tokval); |
299 | f = rexp1(critical); |
300 | if (!f) |
301 | return NULL; |
302 | if (!(is_simple(e) || is_just_unknown(e)) || |
303 | !(is_simple(f) || is_just_unknown(f))) { |
304 | nasm_error(ERR_NONFATAL, "`|' operator may only be applied to" |
305 | " scalar values" ); |
306 | } |
307 | |
308 | if (is_just_unknown(e) || is_just_unknown(f)) |
309 | e = unknown_expr(); |
310 | else |
311 | e = scalarvect((int64_t)(reloc_value(e) || reloc_value(f))); |
312 | } |
313 | return e; |
314 | } |
315 | |
316 | static expr *rexp1(int critical) |
317 | { |
318 | expr *e, *f; |
319 | |
320 | e = rexp2(critical); |
321 | if (!e) |
322 | return NULL; |
323 | |
324 | while (i == TOKEN_DBL_XOR) { |
325 | i = scan(scpriv, tokval); |
326 | f = rexp2(critical); |
327 | if (!f) |
328 | return NULL; |
329 | if (!(is_simple(e) || is_just_unknown(e)) || |
330 | !(is_simple(f) || is_just_unknown(f))) { |
331 | nasm_error(ERR_NONFATAL, "`^' operator may only be applied to" |
332 | " scalar values" ); |
333 | } |
334 | |
335 | if (is_just_unknown(e) || is_just_unknown(f)) |
336 | e = unknown_expr(); |
337 | else |
338 | e = scalarvect((int64_t)(!reloc_value(e) ^ !reloc_value(f))); |
339 | } |
340 | return e; |
341 | } |
342 | |
343 | static expr *rexp2(int critical) |
344 | { |
345 | expr *e, *f; |
346 | |
347 | e = rexp3(critical); |
348 | if (!e) |
349 | return NULL; |
350 | while (i == TOKEN_DBL_AND) { |
351 | i = scan(scpriv, tokval); |
352 | f = rexp3(critical); |
353 | if (!f) |
354 | return NULL; |
355 | if (!(is_simple(e) || is_just_unknown(e)) || |
356 | !(is_simple(f) || is_just_unknown(f))) { |
357 | nasm_error(ERR_NONFATAL, "`&' operator may only be applied to" |
358 | " scalar values" ); |
359 | } |
360 | if (is_just_unknown(e) || is_just_unknown(f)) |
361 | e = unknown_expr(); |
362 | else |
363 | e = scalarvect((int64_t)(reloc_value(e) && reloc_value(f))); |
364 | } |
365 | return e; |
366 | } |
367 | |
368 | static expr *rexp3(int critical) |
369 | { |
370 | expr *e, *f; |
371 | int64_t v; |
372 | |
373 | e = expr0(critical); |
374 | if (!e) |
375 | return NULL; |
376 | |
377 | while (i == TOKEN_EQ || i == TOKEN_LT || i == TOKEN_GT || |
378 | i == TOKEN_NE || i == TOKEN_LE || i == TOKEN_GE) { |
379 | int j = i; |
380 | i = scan(scpriv, tokval); |
381 | f = expr0(critical); |
382 | if (!f) |
383 | return NULL; |
384 | |
385 | e = add_vectors(e, scalar_mult(f, -1L, false)); |
386 | |
387 | switch (j) { |
388 | case TOKEN_EQ: |
389 | case TOKEN_NE: |
390 | if (is_unknown(e)) |
391 | v = -1; /* means unknown */ |
392 | else if (!is_really_simple(e) || reloc_value(e) != 0) |
393 | v = (j == TOKEN_NE); /* unequal, so return true if NE */ |
394 | else |
395 | v = (j == TOKEN_EQ); /* equal, so return true if EQ */ |
396 | break; |
397 | default: |
398 | if (is_unknown(e)) |
399 | v = -1; /* means unknown */ |
400 | else if (!is_really_simple(e)) { |
401 | nasm_error(ERR_NONFATAL, |
402 | "`%s': operands differ by a non-scalar" , |
403 | (j == TOKEN_LE ? "<=" : j == TOKEN_LT ? "<" : j == |
404 | TOKEN_GE ? ">=" : ">" )); |
405 | v = 0; /* must set it to _something_ */ |
406 | } else { |
407 | int64_t vv = reloc_value(e); |
408 | if (vv == 0) |
409 | v = (j == TOKEN_LE || j == TOKEN_GE); |
410 | else if (vv > 0) |
411 | v = (j == TOKEN_GE || j == TOKEN_GT); |
412 | else /* vv < 0 */ |
413 | v = (j == TOKEN_LE || j == TOKEN_LT); |
414 | } |
415 | break; |
416 | } |
417 | |
418 | if (v == -1) |
419 | e = unknown_expr(); |
420 | else |
421 | e = scalarvect(v); |
422 | } |
423 | return e; |
424 | } |
425 | |
426 | static expr *expr0(int critical) |
427 | { |
428 | expr *e, *f; |
429 | |
430 | e = expr1(critical); |
431 | if (!e) |
432 | return NULL; |
433 | |
434 | while (i == '|') { |
435 | i = scan(scpriv, tokval); |
436 | f = expr1(critical); |
437 | if (!f) |
438 | return NULL; |
439 | if (!(is_simple(e) || is_just_unknown(e)) || |
440 | !(is_simple(f) || is_just_unknown(f))) { |
441 | nasm_error(ERR_NONFATAL, "`|' operator may only be applied to" |
442 | " scalar values" ); |
443 | } |
444 | if (is_just_unknown(e) || is_just_unknown(f)) |
445 | e = unknown_expr(); |
446 | else |
447 | e = scalarvect(reloc_value(e) | reloc_value(f)); |
448 | } |
449 | return e; |
450 | } |
451 | |
452 | static expr *expr1(int critical) |
453 | { |
454 | expr *e, *f; |
455 | |
456 | e = expr2(critical); |
457 | if (!e) |
458 | return NULL; |
459 | |
460 | while (i == '^') { |
461 | i = scan(scpriv, tokval); |
462 | f = expr2(critical); |
463 | if (!f) |
464 | return NULL; |
465 | if (!(is_simple(e) || is_just_unknown(e)) || |
466 | !(is_simple(f) || is_just_unknown(f))) { |
467 | nasm_error(ERR_NONFATAL, "`^' operator may only be applied to" |
468 | " scalar values" ); |
469 | } |
470 | if (is_just_unknown(e) || is_just_unknown(f)) |
471 | e = unknown_expr(); |
472 | else |
473 | e = scalarvect(reloc_value(e) ^ reloc_value(f)); |
474 | } |
475 | return e; |
476 | } |
477 | |
478 | static expr *expr2(int critical) |
479 | { |
480 | expr *e, *f; |
481 | |
482 | e = expr3(critical); |
483 | if (!e) |
484 | return NULL; |
485 | |
486 | while (i == '&') { |
487 | i = scan(scpriv, tokval); |
488 | f = expr3(critical); |
489 | if (!f) |
490 | return NULL; |
491 | if (!(is_simple(e) || is_just_unknown(e)) || |
492 | !(is_simple(f) || is_just_unknown(f))) { |
493 | nasm_error(ERR_NONFATAL, "`&' operator may only be applied to" |
494 | " scalar values" ); |
495 | } |
496 | if (is_just_unknown(e) || is_just_unknown(f)) |
497 | e = unknown_expr(); |
498 | else |
499 | e = scalarvect(reloc_value(e) & reloc_value(f)); |
500 | } |
501 | return e; |
502 | } |
503 | |
504 | static expr *expr3(int critical) |
505 | { |
506 | expr *e, *f; |
507 | |
508 | e = expr4(critical); |
509 | if (!e) |
510 | return NULL; |
511 | |
512 | while (i == TOKEN_SHL || i == TOKEN_SHR) { |
513 | int j = i; |
514 | i = scan(scpriv, tokval); |
515 | f = expr4(critical); |
516 | if (!f) |
517 | return NULL; |
518 | if (!(is_simple(e) || is_just_unknown(e)) || |
519 | !(is_simple(f) || is_just_unknown(f))) { |
520 | nasm_error(ERR_NONFATAL, "shift operator may only be applied to" |
521 | " scalar values" ); |
522 | } else if (is_just_unknown(e) || is_just_unknown(f)) { |
523 | e = unknown_expr(); |
524 | } else |
525 | switch (j) { |
526 | case TOKEN_SHL: |
527 | e = scalarvect(reloc_value(e) << reloc_value(f)); |
528 | break; |
529 | case TOKEN_SHR: |
530 | e = scalarvect(((uint64_t)reloc_value(e)) >> |
531 | reloc_value(f)); |
532 | break; |
533 | } |
534 | } |
535 | return e; |
536 | } |
537 | |
538 | static expr *expr4(int critical) |
539 | { |
540 | expr *e, *f; |
541 | |
542 | e = expr5(critical); |
543 | if (!e) |
544 | return NULL; |
545 | while (i == '+' || i == '-') { |
546 | int j = i; |
547 | i = scan(scpriv, tokval); |
548 | f = expr5(critical); |
549 | if (!f) |
550 | return NULL; |
551 | switch (j) { |
552 | case '+': |
553 | e = add_vectors(e, f); |
554 | break; |
555 | case '-': |
556 | e = add_vectors(e, scalar_mult(f, -1L, false)); |
557 | break; |
558 | } |
559 | } |
560 | return e; |
561 | } |
562 | |
563 | static expr *expr5(int critical) |
564 | { |
565 | expr *e, *f; |
566 | |
567 | e = expr6(critical); |
568 | if (!e) |
569 | return NULL; |
570 | while (i == '*' || i == '/' || i == '%' || |
571 | i == TOKEN_SDIV || i == TOKEN_SMOD) { |
572 | int j = i; |
573 | i = scan(scpriv, tokval); |
574 | f = expr6(critical); |
575 | if (!f) |
576 | return NULL; |
577 | if (j != '*' && (!(is_simple(e) || is_just_unknown(e)) || |
578 | !(is_simple(f) || is_just_unknown(f)))) { |
579 | nasm_error(ERR_NONFATAL, "division operator may only be applied to" |
580 | " scalar values" ); |
581 | return NULL; |
582 | } |
583 | if (j != '*' && !is_just_unknown(f) && reloc_value(f) == 0) { |
584 | nasm_error(ERR_NONFATAL, "division by zero" ); |
585 | return NULL; |
586 | } |
587 | switch (j) { |
588 | case '*': |
589 | if (is_simple(e)) |
590 | e = scalar_mult(f, reloc_value(e), true); |
591 | else if (is_simple(f)) |
592 | e = scalar_mult(e, reloc_value(f), true); |
593 | else if (is_just_unknown(e) && is_just_unknown(f)) |
594 | e = unknown_expr(); |
595 | else { |
596 | nasm_error(ERR_NONFATAL, "unable to multiply two " |
597 | "non-scalar objects" ); |
598 | return NULL; |
599 | } |
600 | break; |
601 | case '/': |
602 | if (is_just_unknown(e) || is_just_unknown(f)) |
603 | e = unknown_expr(); |
604 | else |
605 | e = scalarvect(((uint64_t)reloc_value(e)) / |
606 | ((uint64_t)reloc_value(f))); |
607 | break; |
608 | case '%': |
609 | if (is_just_unknown(e) || is_just_unknown(f)) |
610 | e = unknown_expr(); |
611 | else |
612 | e = scalarvect(((uint64_t)reloc_value(e)) % |
613 | ((uint64_t)reloc_value(f))); |
614 | break; |
615 | case TOKEN_SDIV: |
616 | if (is_just_unknown(e) || is_just_unknown(f)) |
617 | e = unknown_expr(); |
618 | else |
619 | e = scalarvect(((int64_t)reloc_value(e)) / |
620 | ((int64_t)reloc_value(f))); |
621 | break; |
622 | case TOKEN_SMOD: |
623 | if (is_just_unknown(e) || is_just_unknown(f)) |
624 | e = unknown_expr(); |
625 | else |
626 | e = scalarvect(((int64_t)reloc_value(e)) % |
627 | ((int64_t)reloc_value(f))); |
628 | break; |
629 | } |
630 | } |
631 | return e; |
632 | } |
633 | |
634 | static expr *eval_floatize(enum floatize type) |
635 | { |
636 | uint8_t result[16], *p; /* Up to 128 bits */ |
637 | static const struct { |
638 | int bytes, start, len; |
639 | } formats[] = { |
640 | { 1, 0, 1 }, /* FLOAT_8 */ |
641 | { 2, 0, 2 }, /* FLOAT_16 */ |
642 | { 4, 0, 4 }, /* FLOAT_32 */ |
643 | { 8, 0, 8 }, /* FLOAT_64 */ |
644 | { 10, 0, 8 }, /* FLOAT_80M */ |
645 | { 10, 8, 2 }, /* FLOAT_80E */ |
646 | { 16, 0, 8 }, /* FLOAT_128L */ |
647 | { 16, 8, 8 }, /* FLOAT_128H */ |
648 | }; |
649 | int sign = 1; |
650 | int64_t val; |
651 | int j; |
652 | |
653 | i = scan(scpriv, tokval); |
654 | if (i != '(') { |
655 | nasm_error(ERR_NONFATAL, "expecting `('" ); |
656 | return NULL; |
657 | } |
658 | i = scan(scpriv, tokval); |
659 | if (i == '-' || i == '+') { |
660 | sign = (i == '-') ? -1 : 1; |
661 | i = scan(scpriv, tokval); |
662 | } |
663 | if (i != TOKEN_FLOAT) { |
664 | nasm_error(ERR_NONFATAL, "expecting floating-point number" ); |
665 | return NULL; |
666 | } |
667 | if (!float_const(tokval->t_charptr, sign, result, formats[type].bytes)) |
668 | return NULL; |
669 | i = scan(scpriv, tokval); |
670 | if (i != ')') { |
671 | nasm_error(ERR_NONFATAL, "expecting `)'" ); |
672 | return NULL; |
673 | } |
674 | |
675 | p = result+formats[type].start+formats[type].len; |
676 | val = 0; |
677 | for (j = formats[type].len; j; j--) { |
678 | p--; |
679 | val = (val << 8) + *p; |
680 | } |
681 | |
682 | begintemp(); |
683 | addtotemp(EXPR_SIMPLE, val); |
684 | |
685 | i = scan(scpriv, tokval); |
686 | return finishtemp(); |
687 | } |
688 | |
689 | static expr *eval_strfunc(enum strfunc type) |
690 | { |
691 | char *string; |
692 | size_t string_len; |
693 | int64_t val; |
694 | bool parens, rn_warn; |
695 | |
696 | parens = false; |
697 | i = scan(scpriv, tokval); |
698 | if (i == '(') { |
699 | parens = true; |
700 | i = scan(scpriv, tokval); |
701 | } |
702 | if (i != TOKEN_STR) { |
703 | nasm_error(ERR_NONFATAL, "expecting string" ); |
704 | return NULL; |
705 | } |
706 | string_len = string_transform(tokval->t_charptr, tokval->t_inttwo, |
707 | &string, type); |
708 | if (string_len == (size_t)-1) { |
709 | nasm_error(ERR_NONFATAL, "invalid string for transform" ); |
710 | return NULL; |
711 | } |
712 | |
713 | val = readstrnum(string, string_len, &rn_warn); |
714 | if (parens) { |
715 | i = scan(scpriv, tokval); |
716 | if (i != ')') { |
717 | nasm_error(ERR_NONFATAL, "expecting `)'" ); |
718 | return NULL; |
719 | } |
720 | } |
721 | |
722 | if (rn_warn) |
723 | nasm_error(ERR_WARNING|ERR_PASS1, "character constant too long" ); |
724 | |
725 | begintemp(); |
726 | addtotemp(EXPR_SIMPLE, val); |
727 | |
728 | i = scan(scpriv, tokval); |
729 | return finishtemp(); |
730 | } |
731 | |
732 | static int64_t eval_ifunc(int64_t val, enum ifunc func) |
733 | { |
734 | int errtype; |
735 | uint64_t uval = (uint64_t)val; |
736 | int64_t rv; |
737 | |
738 | switch (func) { |
739 | case IFUNC_ILOG2E: |
740 | case IFUNC_ILOG2W: |
741 | errtype = (func == IFUNC_ILOG2E) ? ERR_NONFATAL : ERR_WARNING; |
742 | |
743 | if (!is_power2(uval)) |
744 | nasm_error(errtype, "ilog2 argument is not a power of two" ); |
745 | /* fall through */ |
746 | case IFUNC_ILOG2F: |
747 | rv = ilog2_64(uval); |
748 | break; |
749 | |
750 | case IFUNC_ILOG2C: |
751 | rv = (uval < 2) ? 0 : ilog2_64(uval-1) + 1; |
752 | break; |
753 | |
754 | default: |
755 | nasm_panic(0, "invalid IFUNC token %d" , func); |
756 | rv = 0; |
757 | break; |
758 | } |
759 | |
760 | return rv; |
761 | } |
762 | |
763 | static expr *expr6(int critical) |
764 | { |
765 | int32_t type; |
766 | expr *e; |
767 | int32_t label_seg; |
768 | int64_t label_ofs; |
769 | int64_t tmpval; |
770 | bool rn_warn; |
771 | const char *scope; |
772 | |
773 | if (++deadman > nasm_limit[LIMIT_EVAL]) { |
774 | nasm_error(ERR_NONFATAL, "expression too long" ); |
775 | return NULL; |
776 | } |
777 | |
778 | switch (i) { |
779 | case '-': |
780 | i = scan(scpriv, tokval); |
781 | e = expr6(critical); |
782 | if (!e) |
783 | return NULL; |
784 | return scalar_mult(e, -1L, false); |
785 | |
786 | case '+': |
787 | i = scan(scpriv, tokval); |
788 | return expr6(critical); |
789 | |
790 | case '~': |
791 | i = scan(scpriv, tokval); |
792 | e = expr6(critical); |
793 | if (!e) |
794 | return NULL; |
795 | if (is_just_unknown(e)) |
796 | return unknown_expr(); |
797 | else if (!is_simple(e)) { |
798 | nasm_error(ERR_NONFATAL, "`~' operator may only be applied to" |
799 | " scalar values" ); |
800 | return NULL; |
801 | } |
802 | return scalarvect(~reloc_value(e)); |
803 | |
804 | case '!': |
805 | i = scan(scpriv, tokval); |
806 | e = expr6(critical); |
807 | if (!e) |
808 | return NULL; |
809 | if (is_just_unknown(e)) |
810 | return unknown_expr(); |
811 | else if (!is_simple(e)) { |
812 | nasm_error(ERR_NONFATAL, "`!' operator may only be applied to" |
813 | " scalar values" ); |
814 | return NULL; |
815 | } |
816 | return scalarvect(!reloc_value(e)); |
817 | |
818 | case TOKEN_IFUNC: |
819 | { |
820 | enum ifunc func = tokval->t_integer; |
821 | i = scan(scpriv, tokval); |
822 | e = expr6(critical); |
823 | if (!e) |
824 | return NULL; |
825 | if (is_just_unknown(e)) |
826 | return unknown_expr(); |
827 | else if (!is_simple(e)) { |
828 | nasm_error(ERR_NONFATAL, "function may only be applied to" |
829 | " scalar values" ); |
830 | return NULL; |
831 | } |
832 | return scalarvect(eval_ifunc(reloc_value(e), func)); |
833 | } |
834 | |
835 | case TOKEN_SEG: |
836 | i = scan(scpriv, tokval); |
837 | e = expr6(critical); |
838 | if (!e) |
839 | return NULL; |
840 | e = segment_part(e); |
841 | if (!e) |
842 | return NULL; |
843 | if (is_unknown(e) && critical) { |
844 | nasm_error(ERR_NONFATAL, "unable to determine segment base" ); |
845 | return NULL; |
846 | } |
847 | return e; |
848 | |
849 | case TOKEN_FLOATIZE: |
850 | return eval_floatize(tokval->t_integer); |
851 | |
852 | case TOKEN_STRFUNC: |
853 | return eval_strfunc(tokval->t_integer); |
854 | |
855 | case '(': |
856 | i = scan(scpriv, tokval); |
857 | e = bexpr(critical); |
858 | if (!e) |
859 | return NULL; |
860 | if (i != ')') { |
861 | nasm_error(ERR_NONFATAL, "expecting `)'" ); |
862 | return NULL; |
863 | } |
864 | i = scan(scpriv, tokval); |
865 | return e; |
866 | |
867 | case TOKEN_NUM: |
868 | case TOKEN_STR: |
869 | case TOKEN_REG: |
870 | case TOKEN_ID: |
871 | case TOKEN_INSN: /* Opcodes that occur here are really labels */ |
872 | case TOKEN_HERE: |
873 | case TOKEN_BASE: |
874 | case TOKEN_DECORATOR: |
875 | begintemp(); |
876 | switch (i) { |
877 | case TOKEN_NUM: |
878 | addtotemp(EXPR_SIMPLE, tokval->t_integer); |
879 | break; |
880 | case TOKEN_STR: |
881 | tmpval = readstrnum(tokval->t_charptr, tokval->t_inttwo, &rn_warn); |
882 | if (rn_warn) |
883 | nasm_error(ERR_WARNING|ERR_PASS1, "character constant too long" ); |
884 | addtotemp(EXPR_SIMPLE, tmpval); |
885 | break; |
886 | case TOKEN_REG: |
887 | addtotemp(tokval->t_integer, 1L); |
888 | if (hint && hint->type == EAH_NOHINT) |
889 | hint->base = tokval->t_integer, hint->type = EAH_MAKEBASE; |
890 | break; |
891 | case TOKEN_ID: |
892 | case TOKEN_INSN: |
893 | case TOKEN_HERE: |
894 | case TOKEN_BASE: |
895 | /* |
896 | * If !location.known, this indicates that no |
897 | * symbol, Here or Base references are valid because we |
898 | * are in preprocess-only mode. |
899 | */ |
900 | if (!location.known) { |
901 | nasm_error(ERR_NONFATAL, |
902 | "%s not supported in preprocess-only mode" , |
903 | (i == TOKEN_HERE ? "`$'" : |
904 | i == TOKEN_BASE ? "`$$'" : |
905 | "symbol references" )); |
906 | addtotemp(EXPR_UNKNOWN, 1L); |
907 | break; |
908 | } |
909 | |
910 | type = EXPR_SIMPLE; /* might get overridden by UNKNOWN */ |
911 | if (i == TOKEN_BASE) { |
912 | label_seg = in_absolute ? absolute.segment : location.segment; |
913 | label_ofs = 0; |
914 | } else if (i == TOKEN_HERE) { |
915 | label_seg = in_absolute ? absolute.segment : location.segment; |
916 | label_ofs = in_absolute ? absolute.offset : location.offset; |
917 | } else { |
918 | if (!lookup_label(tokval->t_charptr, &label_seg, &label_ofs)) { |
919 | scope = local_scope(tokval->t_charptr); |
920 | if (critical == 2) { |
921 | nasm_error(ERR_NONFATAL, "symbol `%s%s' undefined" , |
922 | scope,tokval->t_charptr); |
923 | return NULL; |
924 | } else if (critical == 1) { |
925 | nasm_error(ERR_NONFATAL, |
926 | "symbol `%s%s' not defined before use" , |
927 | scope,tokval->t_charptr); |
928 | return NULL; |
929 | } else { |
930 | if (opflags) |
931 | *opflags |= OPFLAG_FORWARD; |
932 | type = EXPR_UNKNOWN; |
933 | label_seg = NO_SEG; |
934 | label_ofs = 1; |
935 | } |
936 | } |
937 | if (opflags && is_extern(tokval->t_charptr)) |
938 | *opflags |= OPFLAG_EXTERN; |
939 | } |
940 | addtotemp(type, label_ofs); |
941 | if (label_seg != NO_SEG) |
942 | addtotemp(EXPR_SEGBASE + label_seg, 1L); |
943 | break; |
944 | case TOKEN_DECORATOR: |
945 | addtotemp(EXPR_RDSAE, tokval->t_integer); |
946 | break; |
947 | } |
948 | i = scan(scpriv, tokval); |
949 | return finishtemp(); |
950 | |
951 | default: |
952 | nasm_error(ERR_NONFATAL, "expression syntax error" ); |
953 | return NULL; |
954 | } |
955 | } |
956 | |
957 | expr *evaluate(scanner sc, void *scprivate, struct tokenval *tv, |
958 | int *fwref, int critical, struct eval_hints *hints) |
959 | { |
960 | expr *e; |
961 | expr *f = NULL; |
962 | |
963 | deadman = 0; |
964 | |
965 | hint = hints; |
966 | if (hint) |
967 | hint->type = EAH_NOHINT; |
968 | |
969 | if (critical & CRITICAL) { |
970 | critical &= ~CRITICAL; |
971 | bexpr = rexp0; |
972 | } else |
973 | bexpr = expr0; |
974 | |
975 | scan = sc; |
976 | scpriv = scprivate; |
977 | tokval = tv; |
978 | opflags = fwref; |
979 | |
980 | if (tokval->t_type == TOKEN_INVALID) |
981 | i = scan(scpriv, tokval); |
982 | else |
983 | i = tokval->t_type; |
984 | |
985 | while (ntempexprs) /* initialize temporary storage */ |
986 | nasm_free(tempexprs[--ntempexprs]); |
987 | |
988 | e = bexpr(critical); |
989 | if (!e) |
990 | return NULL; |
991 | |
992 | if (i == TOKEN_WRT) { |
993 | i = scan(scpriv, tokval); /* eat the WRT */ |
994 | f = expr6(critical); |
995 | if (!f) |
996 | return NULL; |
997 | } |
998 | e = scalar_mult(e, 1L, false); /* strip far-absolute segment part */ |
999 | if (f) { |
1000 | expr *g; |
1001 | if (is_just_unknown(f)) |
1002 | g = unknown_expr(); |
1003 | else { |
1004 | int64_t value; |
1005 | begintemp(); |
1006 | if (!is_reloc(f)) { |
1007 | nasm_error(ERR_NONFATAL, "invalid right-hand operand to WRT" ); |
1008 | return NULL; |
1009 | } |
1010 | value = reloc_seg(f); |
1011 | if (value == NO_SEG) |
1012 | value = reloc_value(f) | SEG_ABS; |
1013 | else if (!(value & SEG_ABS) && !(value % 2) && critical) { |
1014 | nasm_error(ERR_NONFATAL, "invalid right-hand operand to WRT" ); |
1015 | return NULL; |
1016 | } |
1017 | addtotemp(EXPR_WRT, value); |
1018 | g = finishtemp(); |
1019 | } |
1020 | e = add_vectors(e, g); |
1021 | } |
1022 | return e; |
1023 | } |
1024 | |