1 /* eval.c expression evaluator for the Netwide Assembler
3 * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
4 * Julian Hall. All rights reserved. The software is
5 * redistributable under the licence given in the file "Licence"
6 * distributed in the NASM archive.
8 * initial version 27/iii/95 by Simon Tatham
24 #define TEMPEXPRS_DELTA 128
25 #define TEMPEXPR_DELTA 8
27 static scanner scan; /* Address of scanner routine */
28 static efunc error; /* Address of error reporting routine */
29 static lfunc labelfunc; /* Address of label routine */
31 static struct ofmt *outfmt; /* Structure of addresses of output routines */
33 static expr **tempexprs = NULL;
34 static int ntempexprs;
35 static int tempexprs_size = 0;
37 static expr *tempexpr;
39 static int tempexpr_size;
41 static struct tokenval *tokval; /* The current token */
42 static int i; /* The t_type of tokval */
45 static loc_t *location; /* Pointer to current line's segment,offset */
48 static struct eval_hints *hint;
50 extern int in_abs_seg; /* ABSOLUTE segment flag */
51 extern int32_t abs_seg; /* ABSOLUTE segment */
52 extern int32_t abs_offset; /* ABSOLUTE segment offset */
55 * Unimportant cleanup is done to avoid confusing people who are trying
56 * to debug real memory leaks
58 void eval_cleanup(void)
61 nasm_free(tempexprs[--ntempexprs]);
66 * Construct a temporary expression.
68 static void begintemp(void)
71 tempexpr_size = ntempexpr = 0;
74 static void addtotemp(int32_t type, int64_t value)
76 while (ntempexpr >= tempexpr_size) {
77 tempexpr_size += TEMPEXPR_DELTA;
78 tempexpr = nasm_realloc(tempexpr,
79 tempexpr_size * sizeof(*tempexpr));
81 tempexpr[ntempexpr].type = type;
82 tempexpr[ntempexpr++].value = value;
85 static expr *finishtemp(void)
87 addtotemp(0L, 0L); /* terminate */
88 while (ntempexprs >= tempexprs_size) {
89 tempexprs_size += TEMPEXPRS_DELTA;
90 tempexprs = nasm_realloc(tempexprs,
91 tempexprs_size * sizeof(*tempexprs));
93 return tempexprs[ntempexprs++] = tempexpr;
97 * Add two vector datatypes. We have some bizarre behaviour on far-
98 * absolute segment types: we preserve them during addition _only_
99 * if one of the segments is a truly pure scalar.
101 static expr *add_vectors(expr * p, expr * q)
105 preserve = is_really_simple(p) || is_really_simple(q);
109 while (p->type && q->type &&
110 p->type < EXPR_SEGBASE + SEG_ABS &&
111 q->type < EXPR_SEGBASE + SEG_ABS) {
114 if (p->type > q->type) {
115 addtotemp(q->type, q->value);
116 lasttype = q++->type;
117 } else if (p->type < q->type) {
118 addtotemp(p->type, p->value);
119 lasttype = p++->type;
120 } else { /* *p and *q have same type */
121 int32_t sum = p->value + q->value;
123 addtotemp(p->type, sum);
127 if (lasttype == EXPR_UNKNOWN) {
131 while (p->type && (preserve || p->type < EXPR_SEGBASE + SEG_ABS)) {
132 addtotemp(p->type, p->value);
135 while (q->type && (preserve || q->type < EXPR_SEGBASE + SEG_ABS)) {
136 addtotemp(q->type, q->value);
144 * Multiply a vector by a scalar. Strip far-absolute segment part
147 * Explicit treatment of UNKNOWN is not required in this routine,
148 * since it will silently do the Right Thing anyway.
150 * If `affect_hints' is set, we also change the hint type to
151 * NOTBASE if a MAKEBASE hint points at a register being
152 * multiplied. This allows [eax*1+ebx] to hint EBX rather than EAX
153 * as the base register.
155 static expr *scalar_mult(expr * vect, int32_t scalar, int affect_hints)
159 while (p->type && p->type < EXPR_SEGBASE + SEG_ABS) {
160 p->value = scalar * (p->value);
161 if (hint && hint->type == EAH_MAKEBASE &&
162 p->type == hint->base && affect_hints)
163 hint->type = EAH_NOTBASE;
171 static expr *scalarvect(int32_t scalar)
174 addtotemp(EXPR_SIMPLE, scalar);
178 static expr *unknown_expr(void)
181 addtotemp(EXPR_UNKNOWN, 1L);
186 * The SEG operator: calculate the segment part of a relocatable
187 * value. Return NULL, as usual, if an error occurs. Report the
190 static expr *segment_part(expr * e)
195 return unknown_expr();
198 error(ERR_NONFATAL, "cannot apply SEG to a non-relocatable value");
204 error(ERR_NONFATAL, "cannot apply SEG to a non-relocatable value");
206 } else if (seg & SEG_ABS) {
207 return scalarvect(seg & ~SEG_ABS);
208 } else if (seg & 1) {
209 error(ERR_NONFATAL, "SEG applied to something which"
210 " is already a segment base");
213 int32_t base = outfmt->segbase(seg + 1);
216 addtotemp((base == NO_SEG ? EXPR_UNKNOWN : EXPR_SEGBASE + base),
223 * Recursive-descent parser. Called with a single boolean operand,
224 * which is TRUE if the evaluation is critical (i.e. unresolved
225 * symbols are an error condition). Must update the global `i' to
226 * reflect the token after the parsed string. May return NULL.
228 * evaluate() should report its own errors: on return it is assumed
229 * that if NULL has been returned, the error has already been
236 * expr : bexpr [ WRT expr6 ]
237 * bexpr : rexp0 or expr0 depending on relative-mode setting
238 * rexp0 : rexp1 [ {||} rexp1...]
239 * rexp1 : rexp2 [ {^^} rexp2...]
240 * rexp2 : rexp3 [ {&&} rexp3...]
241 * rexp3 : expr0 [ {=,==,<>,!=,<,>,<=,>=} expr0 ]
242 * expr0 : expr1 [ {|} expr1...]
243 * expr1 : expr2 [ {^} expr2...]
244 * expr2 : expr3 [ {&} expr3...]
245 * expr3 : expr4 [ {<<,>>} expr4...]
246 * expr4 : expr5 [ {+,-} expr5...]
247 * expr5 : expr6 [ {*,/,%,//,%%} expr6...]
248 * expr6 : { ~,+,-,SEG } expr6
255 static expr *rexp0(int), *rexp1(int), *rexp2(int), *rexp3(int);
257 static expr *expr0(int), *expr1(int), *expr2(int), *expr3(int);
258 static expr *expr4(int), *expr5(int), *expr6(int);
260 static expr *(*bexpr) (int);
262 static expr *rexp0(int critical)
270 while (i == TOKEN_DBL_OR) {
271 i = scan(scpriv, tokval);
275 if (!(is_simple(e) || is_just_unknown(e)) ||
276 !(is_simple(f) || is_just_unknown(f))) {
277 error(ERR_NONFATAL, "`|' operator may only be applied to"
281 if (is_just_unknown(e) || is_just_unknown(f))
284 e = scalarvect((int32_t)(reloc_value(e) || reloc_value(f)));
289 static expr *rexp1(int critical)
297 while (i == TOKEN_DBL_XOR) {
298 i = scan(scpriv, tokval);
302 if (!(is_simple(e) || is_just_unknown(e)) ||
303 !(is_simple(f) || is_just_unknown(f))) {
304 error(ERR_NONFATAL, "`^' operator may only be applied to"
308 if (is_just_unknown(e) || is_just_unknown(f))
311 e = scalarvect((int32_t)(!reloc_value(e) ^ !reloc_value(f)));
316 static expr *rexp2(int critical)
323 while (i == TOKEN_DBL_AND) {
324 i = scan(scpriv, tokval);
328 if (!(is_simple(e) || is_just_unknown(e)) ||
329 !(is_simple(f) || is_just_unknown(f))) {
330 error(ERR_NONFATAL, "`&' operator may only be applied to"
333 if (is_just_unknown(e) || is_just_unknown(f))
336 e = scalarvect((int32_t)(reloc_value(e) && reloc_value(f)));
341 static expr *rexp3(int critical)
350 while (i == TOKEN_EQ || i == TOKEN_LT || i == TOKEN_GT ||
351 i == TOKEN_NE || i == TOKEN_LE || i == TOKEN_GE) {
353 i = scan(scpriv, tokval);
358 e = add_vectors(e, scalar_mult(f, -1L, FALSE));
364 v = -1; /* means unknown */
365 else if (!is_really_simple(e) || reloc_value(e) != 0)
366 v = (j == TOKEN_NE); /* unequal, so return TRUE if NE */
368 v = (j == TOKEN_EQ); /* equal, so return TRUE if EQ */
372 v = -1; /* means unknown */
373 else if (!is_really_simple(e)) {
375 "`%s': operands differ by a non-scalar",
376 (j == TOKEN_LE ? "<=" : j == TOKEN_LT ? "<" : j ==
377 TOKEN_GE ? ">=" : ">"));
378 v = 0; /* must set it to _something_ */
380 int vv = reloc_value(e);
382 v = (j == TOKEN_LE || j == TOKEN_GE);
384 v = (j == TOKEN_GE || j == TOKEN_GT);
386 v = (j == TOKEN_LE || j == TOKEN_LT);
399 static expr *expr0(int critical)
408 i = scan(scpriv, tokval);
412 if (!(is_simple(e) || is_just_unknown(e)) ||
413 !(is_simple(f) || is_just_unknown(f))) {
414 error(ERR_NONFATAL, "`|' operator may only be applied to"
417 if (is_just_unknown(e) || is_just_unknown(f))
420 e = scalarvect(reloc_value(e) | reloc_value(f));
425 static expr *expr1(int critical)
434 i = scan(scpriv, tokval);
438 if (!(is_simple(e) || is_just_unknown(e)) ||
439 !(is_simple(f) || is_just_unknown(f))) {
440 error(ERR_NONFATAL, "`^' operator may only be applied to"
443 if (is_just_unknown(e) || is_just_unknown(f))
446 e = scalarvect(reloc_value(e) ^ reloc_value(f));
451 static expr *expr2(int critical)
460 i = scan(scpriv, tokval);
464 if (!(is_simple(e) || is_just_unknown(e)) ||
465 !(is_simple(f) || is_just_unknown(f))) {
466 error(ERR_NONFATAL, "`&' operator may only be applied to"
469 if (is_just_unknown(e) || is_just_unknown(f))
472 e = scalarvect(reloc_value(e) & reloc_value(f));
477 static expr *expr3(int critical)
485 while (i == TOKEN_SHL || i == TOKEN_SHR) {
487 i = scan(scpriv, tokval);
491 if (!(is_simple(e) || is_just_unknown(e)) ||
492 !(is_simple(f) || is_just_unknown(f))) {
493 error(ERR_NONFATAL, "shift operator may only be applied to"
495 } else if (is_just_unknown(e) || is_just_unknown(f)) {
500 e = scalarvect(reloc_value(e) << reloc_value(f));
503 e = scalarvect(((uint32_t)reloc_value(e)) >>
511 static expr *expr4(int critical)
518 while (i == '+' || i == '-') {
520 i = scan(scpriv, tokval);
526 e = add_vectors(e, f);
529 e = add_vectors(e, scalar_mult(f, -1L, FALSE));
536 static expr *expr5(int critical)
543 while (i == '*' || i == '/' || i == '%' ||
544 i == TOKEN_SDIV || i == TOKEN_SMOD) {
546 i = scan(scpriv, tokval);
550 if (j != '*' && (!(is_simple(e) || is_just_unknown(e)) ||
551 !(is_simple(f) || is_just_unknown(f)))) {
552 error(ERR_NONFATAL, "division operator may only be applied to"
556 if (j != '*' && !is_unknown(f) && reloc_value(f) == 0) {
557 error(ERR_NONFATAL, "division by zero");
563 e = scalar_mult(f, reloc_value(e), TRUE);
564 else if (is_simple(f))
565 e = scalar_mult(e, reloc_value(f), TRUE);
566 else if (is_just_unknown(e) && is_just_unknown(f))
569 error(ERR_NONFATAL, "unable to multiply two "
570 "non-scalar objects");
575 if (is_just_unknown(e) || is_just_unknown(f))
578 e = scalarvect(((uint32_t)reloc_value(e)) /
579 ((uint32_t)reloc_value(f)));
582 if (is_just_unknown(e) || is_just_unknown(f))
585 e = scalarvect(((uint32_t)reloc_value(e)) %
586 ((uint32_t)reloc_value(f)));
589 if (is_just_unknown(e) || is_just_unknown(f))
592 e = scalarvect(((int32_t)reloc_value(e)) /
593 ((int32_t)reloc_value(f)));
596 if (is_just_unknown(e) || is_just_unknown(f))
599 e = scalarvect(((int32_t)reloc_value(e)) %
600 ((int32_t)reloc_value(f)));
607 static expr *eval_floatize(enum floatize type)
609 uint8_t result[16], *p; /* Up to 128 bits */
610 static const struct {
611 int bytes, start, len;
613 { 2, 0, 2 }, /* FLOAT_16 */
614 { 4, 0, 4 }, /* FLOAT_32 */
615 { 8, 0, 8 }, /* FLOAT_64 */
616 { 10, 0, 8 }, /* FLOAT_80M */
617 { 10, 8, 2 }, /* FLOAT_80E */
618 { 16, 0, 8 }, /* FLOAT_128L */
619 { 16, 8, 8 }, /* FLOAT_128H */
625 i = scan(scpriv, tokval);
627 error(ERR_NONFATAL, "expecting `('");
630 i = scan(scpriv, tokval);
631 if (i == '-' || i == '+') {
632 sign = (i == '-') ? -1 : 1;
633 i = scan(scpriv, tokval);
635 if (i != TOKEN_FLOAT) {
636 error(ERR_NONFATAL, "expecting floating-point number");
639 if (!float_const(tokval->t_charptr, sign, result,
640 formats[type].bytes, error))
642 i = scan(scpriv, tokval);
644 error(ERR_NONFATAL, "expecting `)'");
648 p = result+formats[type].start+formats[type].len;
650 for (j = formats[type].len; j; j--) {
652 val = (val << 8) + *p;
656 addtotemp(EXPR_SIMPLE, val);
658 i = scan(scpriv, tokval);
662 static expr *expr6(int critical)
666 int32_t label_seg, label_ofs;
670 i = scan(scpriv, tokval);
674 return scalar_mult(e, -1L, FALSE);
678 i = scan(scpriv, tokval);
679 return expr6(critical);
682 i = scan(scpriv, tokval);
686 if (is_just_unknown(e))
687 return unknown_expr();
688 else if (!is_simple(e)) {
689 error(ERR_NONFATAL, "`~' operator may only be applied to"
693 return scalarvect(~reloc_value(e));
696 i = scan(scpriv, tokval);
700 if (is_just_unknown(e))
701 return unknown_expr();
702 else if (!is_simple(e)) {
703 error(ERR_NONFATAL, "`!' operator may only be applied to"
707 return scalarvect(!reloc_value(e));
710 i = scan(scpriv, tokval);
717 if (is_unknown(e) && critical) {
718 error(ERR_NONFATAL, "unable to determine segment base");
724 return eval_floatize(tokval->t_integer);
727 i = scan(scpriv, tokval);
732 error(ERR_NONFATAL, "expecting `)'");
735 i = scan(scpriv, tokval);
746 addtotemp(EXPR_SIMPLE, tokval->t_integer);
749 addtotemp(tokval->t_integer, 1L);
750 if (hint && hint->type == EAH_NOHINT)
751 hint->base = tokval->t_integer, hint->type = EAH_MAKEBASE;
757 * If !location->known, this indicates that no
758 * symbol, Here or Base references are valid because we
759 * are in preprocess-only mode.
761 if (!location->known) {
763 "%s not supported in preprocess-only mode",
764 (i == TOKEN_ID ? "symbol references" :
765 i == TOKEN_HERE ? "`$'" : "`$$'"));
766 addtotemp(EXPR_UNKNOWN, 1L);
770 type = EXPR_SIMPLE; /* might get overridden by UNKNOWN */
771 if (i == TOKEN_BASE) {
772 label_seg = in_abs_seg ? abs_seg : location->segment;
774 } else if (i == TOKEN_HERE) {
775 label_seg = in_abs_seg ? abs_seg : location->segment;
776 label_ofs = in_abs_seg ? abs_offset : location->offset;
778 if (!labelfunc(tokval->t_charptr, &label_seg, &label_ofs)) {
780 error(ERR_NONFATAL, "symbol `%s' undefined",
783 } else if (critical == 1) {
785 "symbol `%s' not defined before use",
796 if (opflags && is_extern(tokval->t_charptr))
797 *opflags |= OPFLAG_EXTERN;
799 addtotemp(type, label_ofs);
800 if (label_seg != NO_SEG)
801 addtotemp(EXPR_SEGBASE + label_seg, 1L);
804 i = scan(scpriv, tokval);
808 error(ERR_NONFATAL, "expression syntax error");
813 void eval_global_info(struct ofmt *output, lfunc lookup_label,
817 labelfunc = lookup_label;
821 expr *evaluate(scanner sc, void *scprivate, struct tokenval *tv,
822 int *fwref, int critical, efunc report_error,
823 struct eval_hints *hints)
830 hint->type = EAH_NOHINT;
832 if (critical & CRITICAL) {
833 critical &= ~CRITICAL;
841 error = report_error;
844 if (tokval->t_type == TOKEN_INVALID)
845 i = scan(scpriv, tokval);
849 while (ntempexprs) /* initialize temporary storage */
850 nasm_free(tempexprs[--ntempexprs]);
856 if (i == TOKEN_WRT) {
857 i = scan(scpriv, tokval); /* eat the WRT */
862 e = scalar_mult(e, 1L, FALSE); /* strip far-absolute segment part */
865 if (is_just_unknown(f))
871 error(ERR_NONFATAL, "invalid right-hand operand to WRT");
874 value = reloc_seg(f);
876 value = reloc_value(f) | SEG_ABS;
877 else if (!(value & SEG_ABS) && !(value % 2) && critical) {
878 error(ERR_NONFATAL, "invalid right-hand operand to WRT");
881 addtotemp(EXPR_WRT, value);
884 e = add_vectors(e, g);