]> git.saurik.com Git - apple/boot.git/blame - i386/nasm/eval.c
boot-83.2.tar.gz
[apple/boot.git] / i386 / nasm / eval.c
CommitLineData
14c7c974
A
1/*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.1 (the "License"). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24/* eval.c expression evaluator for the Netwide Assembler
25 *
26 * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
27 * Julian Hall. All rights reserved. The software is
28 * redistributable under the licence given in the file "Licence"
29 * distributed in the NASM archive.
30 *
31 * initial version 27/iii/95 by Simon Tatham
32 */
33
34#include <stdio.h>
35#include <stdlib.h>
36#include <stddef.h>
37#include <string.h>
38#include <ctype.h>
39
40#include "nasm.h"
41#include "nasmlib.h"
42#include "eval.h"
43
44static expr **tempexprs = NULL;
45static int ntempexprs, tempexprs_size = 0;
46#define TEMPEXPRS_DELTA 128
47
48static expr *tempexpr;
49static int ntempexpr, tempexpr_size;
50#define TEMPEXPR_DELTA 8
51
52static scanner scan;
53static void *scpriv;
54static struct tokenval *tokval;
55static efunc error;
56static int i;
57static int seg, ofs;
58static char *label = NULL, special_empty_string[] = "";
59static lfunc labelfunc;
60static struct ofmt *outfmt;
61static int *forward;
62
63static struct eval_hints *hint;
64
65/*
66 * Construct a temporary expression.
67 */
68static void begintemp(void) {
69 tempexpr = NULL;
70 tempexpr_size = ntempexpr = 0;
71}
72
73static void addtotemp(long type, long value) {
74 while (ntempexpr >= tempexpr_size) {
75 tempexpr_size += TEMPEXPR_DELTA;
76 tempexpr = nasm_realloc(tempexpr,
77 tempexpr_size*sizeof(*tempexpr));
78 }
79 tempexpr[ntempexpr].type = type;
80 tempexpr[ntempexpr++].value = value;
81}
82
83static expr *finishtemp(void) {
84 addtotemp (0L, 0L); /* terminate */
85 while (ntempexprs >= tempexprs_size) {
86 tempexprs_size += TEMPEXPRS_DELTA;
87 tempexprs = nasm_realloc(tempexprs,
88 tempexprs_size*sizeof(*tempexprs));
89 }
90 return tempexprs[ntempexprs++] = tempexpr;
91}
92
93/*
94 * Add two vector datatypes. We have some bizarre behaviour on far-
95 * absolute segment types: we preserve them during addition _only_
96 * if one of the segments is a truly pure scalar.
97 */
98static expr *add_vectors(expr *p, expr *q) {
99 int preserve;
100
101 preserve = is_really_simple(p) || is_really_simple(q);
102
103 begintemp();
104
105 while (p->type && q->type &&
106 p->type < EXPR_SEGBASE+SEG_ABS &&
107 q->type < EXPR_SEGBASE+SEG_ABS) {
108 int lasttype;
109
110 if (p->type > q->type) {
111 addtotemp(q->type, q->value);
112 lasttype = q++->type;
113 } else if (p->type < q->type) {
114 addtotemp(p->type, p->value);
115 lasttype = p++->type;
116 } else { /* *p and *q have same type */
117 addtotemp(p->type, p->value + q->value);
118 lasttype = p->type;
119 p++, q++;
120 }
121 if (lasttype == EXPR_UNKNOWN) {
122 return finishtemp();
123 }
124 }
125 while (p->type &&
126 (preserve || p->type < EXPR_SEGBASE+SEG_ABS)) {
127 addtotemp(p->type, p->value);
128 p++;
129 }
130 while (q->type &&
131 (preserve || q->type < EXPR_SEGBASE+SEG_ABS)) {
132 addtotemp(q->type, q->value);
133 q++;
134 }
135
136 return finishtemp();
137}
138
139/*
140 * Multiply a vector by a scalar. Strip far-absolute segment part
141 * if present.
142 *
143 * Explicit treatment of UNKNOWN is not required in this routine,
144 * since it will silently do the Right Thing anyway.
145 *
146 * If `affect_hints' is set, we also change the hint type to
147 * NOTBASE if a MAKEBASE hint points at a register being
148 * multiplied. This allows [eax*1+ebx] to hint EBX rather than EAX
149 * as the base register.
150 */
151static expr *scalar_mult(expr *vect, long scalar, int affect_hints) {
152 expr *p = vect;
153
154 while (p->type && p->type < EXPR_SEGBASE+SEG_ABS) {
155 p->value = scalar * (p->value);
156 if (hint && hint->type == EAH_MAKEBASE &&
157 p->type == hint->base && affect_hints)
158 hint->type = EAH_NOTBASE;
159 p++;
160 }
161 p->type = 0;
162
163 return vect;
164}
165
166static expr *scalarvect (long scalar) {
167 begintemp();
168 addtotemp(EXPR_SIMPLE, scalar);
169 return finishtemp();
170}
171
172static expr *unknown_expr (void) {
173 begintemp();
174 addtotemp(EXPR_UNKNOWN, 1L);
175 return finishtemp();
176}
177
178/*
179 * The SEG operator: calculate the segment part of a relocatable
180 * value. Return NULL, as usual, if an error occurs. Report the
181 * error too.
182 */
183static expr *segment_part (expr *e) {
184 long seg;
185
186 if (is_unknown(e))
187 return unknown_expr();
188
189 if (!is_reloc(e)) {
190 error(ERR_NONFATAL, "cannot apply SEG to a non-relocatable value");
191 return NULL;
192 }
193
194 seg = reloc_seg(e);
195 if (seg == NO_SEG) {
196 error(ERR_NONFATAL, "cannot apply SEG to a non-relocatable value");
197 return NULL;
198 } else if (seg & SEG_ABS) {
199 return scalarvect(seg & ~SEG_ABS);
200 } else if (seg & 1) {
201 error(ERR_NONFATAL, "SEG applied to something which"
202 " is already a segment base");
203 return NULL;
204 }
205 else {
206 long base = outfmt->segbase(seg+1);
207
208 begintemp();
209 addtotemp((base == NO_SEG ? EXPR_UNKNOWN : EXPR_SEGBASE+base), 1L);
210 return finishtemp();
211 }
212}
213
214/*
215 * Recursive-descent parser. Called with a single boolean operand,
216 * which is TRUE if the evaluation is critical (i.e. unresolved
217 * symbols are an error condition). Must update the global `i' to
218 * reflect the token after the parsed string. May return NULL.
219 *
220 * evaluate() should report its own errors: on return it is assumed
221 * that if NULL has been returned, the error has already been
222 * reported.
223 */
224
225/*
226 * Grammar parsed is:
227 *
228 * expr : bexpr [ WRT expr6 ]
229 * bexpr : rexp0 or expr0 depending on relative-mode setting
230 * rexp0 : rexp1 [ {||} rexp1...]
231 * rexp1 : rexp2 [ {^^} rexp2...]
232 * rexp2 : rexp3 [ {&&} rexp3...]
233 * rexp3 : expr0 [ {=,==,<>,!=,<,>,<=,>=} expr0 ]
234 * expr0 : expr1 [ {|} expr1...]
235 * expr1 : expr2 [ {^} expr2...]
236 * expr2 : expr3 [ {&} expr3...]
237 * expr3 : expr4 [ {<<,>>} expr4...]
238 * expr4 : expr5 [ {+,-} expr5...]
239 * expr5 : expr6 [ {*,/,%,//,%%} expr6...]
240 * expr6 : { ~,+,-,SEG } expr6
241 * | (bexpr)
242 * | symbol
243 * | $
244 * | number
245 */
246
247static expr *rexp0(int), *rexp1(int), *rexp2(int), *rexp3(int);
248
249static expr *expr0(int), *expr1(int), *expr2(int), *expr3(int);
250static expr *expr4(int), *expr5(int), *expr6(int);
251
252static expr *(*bexpr)(int);
253
254static expr *rexp0(int critical) {
255 expr *e, *f;
256
257 e = rexp1(critical);
258 if (!e)
259 return NULL;
260 while (i == TOKEN_DBL_OR) {
261 i = scan(scpriv, tokval);
262 f = rexp1(critical);
263 if (!f)
264 return NULL;
265 if (!(is_simple(e) || is_just_unknown(e)) ||
266 !(is_simple(f) || is_just_unknown(f))) {
267 error(ERR_NONFATAL, "`|' operator may only be applied to"
268 " scalar values");
269 }
270 if (is_just_unknown(e) || is_just_unknown(f))
271 e = unknown_expr();
272 else
273 e = scalarvect ((long) (reloc_value(e) || reloc_value(f)));
274 }
275 return e;
276}
277
278static expr *rexp1(int critical) {
279 expr *e, *f;
280
281 e = rexp2(critical);
282 if (!e)
283 return NULL;
284 while (i == TOKEN_DBL_XOR) {
285 i = scan(scpriv, tokval);
286 f = rexp2(critical);
287 if (!f)
288 return NULL;
289 if (!(is_simple(e) || is_just_unknown(e)) ||
290 !(is_simple(f) || is_just_unknown(f))) {
291 error(ERR_NONFATAL, "`^' operator may only be applied to"
292 " scalar values");
293 }
294 if (is_just_unknown(e) || is_just_unknown(f))
295 e = unknown_expr();
296 else
297 e = scalarvect ((long) (!reloc_value(e) ^ !reloc_value(f)));
298 }
299 return e;
300}
301
302static expr *rexp2(int critical) {
303 expr *e, *f;
304
305 e = rexp3(critical);
306 if (!e)
307 return NULL;
308 while (i == TOKEN_DBL_AND) {
309 i = scan(scpriv, tokval);
310 f = rexp3(critical);
311 if (!f)
312 return NULL;
313 if (!(is_simple(e) || is_just_unknown(e)) ||
314 !(is_simple(f) || is_just_unknown(f))) {
315 error(ERR_NONFATAL, "`&' operator may only be applied to"
316 " scalar values");
317 }
318 if (is_just_unknown(e) || is_just_unknown(f))
319 e = unknown_expr();
320 else
321 e = scalarvect ((long) (reloc_value(e) && reloc_value(f)));
322 }
323 return e;
324}
325
326static expr *rexp3(int critical) {
327 expr *e, *f;
328 long v;
329
330 e = expr0(critical);
331 if (!e)
332 return NULL;
333 while (i == TOKEN_EQ || i == TOKEN_LT || i == TOKEN_GT ||
334 i == TOKEN_NE || i == TOKEN_LE || i == TOKEN_GE) {
335 int j = i;
336 i = scan(scpriv, tokval);
337 f = expr0(critical);
338 if (!f)
339 return NULL;
340 e = add_vectors (e, scalar_mult(f, -1L, FALSE));
341 switch (j) {
342 case TOKEN_EQ: case TOKEN_NE:
343 if (is_unknown(e))
344 v = -1; /* means unknown */
345 else if (!is_really_simple(e) || reloc_value(e) != 0)
346 v = (j == TOKEN_NE); /* unequal, so return TRUE if NE */
347 else
348 v = (j == TOKEN_EQ); /* equal, so return TRUE if EQ */
349 break;
350 default:
351 if (is_unknown(e))
352 v = -1; /* means unknown */
353 else if (!is_really_simple(e)) {
354 error(ERR_NONFATAL, "`%s': operands differ by a non-scalar",
355 (j == TOKEN_LE ? "<=" : j == TOKEN_LT ? "<" :
356 j == TOKEN_GE ? ">=" : ">"));
357 v = 0; /* must set it to _something_ */
358 } else {
359 int vv = reloc_value(e);
360 if (vv == 0)
361 v = (j == TOKEN_LE || j == TOKEN_GE);
362 else if (vv > 0)
363 v = (j == TOKEN_GE || j == TOKEN_GT);
364 else /* vv < 0 */
365 v = (j == TOKEN_LE || j == TOKEN_LT);
366 }
367 break;
368 }
369 if (v == -1)
370 e = unknown_expr();
371 else
372 e = scalarvect(v);
373 }
374 return e;
375}
376
377static expr *expr0(int critical) {
378 expr *e, *f;
379
380 e = expr1(critical);
381 if (!e)
382 return NULL;
383 while (i == '|') {
384 i = scan(scpriv, tokval);
385 f = expr1(critical);
386 if (!f)
387 return NULL;
388 if (!(is_simple(e) || is_just_unknown(e)) ||
389 !(is_simple(f) || is_just_unknown(f))) {
390 error(ERR_NONFATAL, "`|' operator may only be applied to"
391 " scalar values");
392 }
393 if (is_just_unknown(e) || is_just_unknown(f))
394 e = unknown_expr();
395 else
396 e = scalarvect (reloc_value(e) | reloc_value(f));
397 }
398 return e;
399}
400
401static expr *expr1(int critical) {
402 expr *e, *f;
403
404 e = expr2(critical);
405 if (!e)
406 return NULL;
407 while (i == '^') {
408 i = scan(scpriv, tokval);
409 f = expr2(critical);
410 if (!f)
411 return NULL;
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"
415 " scalar values");
416 }
417 if (is_just_unknown(e) || is_just_unknown(f))
418 e = unknown_expr();
419 else
420 e = scalarvect (reloc_value(e) ^ reloc_value(f));
421 }
422 return e;
423}
424
425static expr *expr2(int critical) {
426 expr *e, *f;
427
428 e = expr3(critical);
429 if (!e)
430 return NULL;
431 while (i == '&') {
432 i = scan(scpriv, tokval);
433 f = expr3(critical);
434 if (!f)
435 return NULL;
436 if (!(is_simple(e) || is_just_unknown(e)) ||
437 !(is_simple(f) || is_just_unknown(f))) {
438 error(ERR_NONFATAL, "`&' operator may only be applied to"
439 " scalar values");
440 }
441 if (is_just_unknown(e) || is_just_unknown(f))
442 e = unknown_expr();
443 else
444 e = scalarvect (reloc_value(e) & reloc_value(f));
445 }
446 return e;
447}
448
449static expr *expr3(int critical) {
450 expr *e, *f;
451
452 e = expr4(critical);
453 if (!e)
454 return NULL;
455 while (i == TOKEN_SHL || i == TOKEN_SHR) {
456 int j = i;
457 i = scan(scpriv, tokval);
458 f = expr4(critical);
459 if (!f)
460 return NULL;
461 if (!(is_simple(e) || is_just_unknown(e)) ||
462 !(is_simple(f) || is_just_unknown(f))) {
463 error(ERR_NONFATAL, "shift operator may only be applied to"
464 " scalar values");
465 } else if (is_just_unknown(e) || is_just_unknown(f)) {
466 e = unknown_expr();
467 } else switch (j) {
468 case TOKEN_SHL:
469 e = scalarvect (reloc_value(e) << reloc_value(f));
470 break;
471 case TOKEN_SHR:
472 e = scalarvect (((unsigned long)reloc_value(e)) >>
473 reloc_value(f));
474 break;
475 }
476 }
477 return e;
478}
479
480static expr *expr4(int critical) {
481 expr *e, *f;
482
483 e = expr5(critical);
484 if (!e)
485 return NULL;
486 while (i == '+' || i == '-') {
487 int j = i;
488 i = scan(scpriv, tokval);
489 f = expr5(critical);
490 if (!f)
491 return NULL;
492 switch (j) {
493 case '+':
494 e = add_vectors (e, f);
495 break;
496 case '-':
497 e = add_vectors (e, scalar_mult(f, -1L, FALSE));
498 break;
499 }
500 }
501 return e;
502}
503
504static expr *expr5(int critical) {
505 expr *e, *f;
506
507 e = expr6(critical);
508 if (!e)
509 return NULL;
510 while (i == '*' || i == '/' || i == '%' ||
511 i == TOKEN_SDIV || i == TOKEN_SMOD) {
512 int j = i;
513 i = scan(scpriv, tokval);
514 f = expr6(critical);
515 if (!f)
516 return NULL;
517 if (j != '*' && (!(is_simple(e) || is_just_unknown(e)) ||
518 !(is_simple(f) || is_just_unknown(f)))) {
519 error(ERR_NONFATAL, "division operator may only be applied to"
520 " scalar values");
521 return NULL;
522 }
523 if (j != '*' && !is_unknown(f) && reloc_value(f) == 0) {
524 error(ERR_NONFATAL, "division by zero");
525 return NULL;
526 }
527 switch (j) {
528 case '*':
529 if (is_simple(e))
530 e = scalar_mult (f, reloc_value(e), TRUE);
531 else if (is_simple(f))
532 e = scalar_mult (e, reloc_value(f), TRUE);
533 else if (is_just_unknown(e) && is_just_unknown(f))
534 e = unknown_expr();
535 else {
536 error(ERR_NONFATAL, "unable to multiply two "
537 "non-scalar objects");
538 return NULL;
539 }
540 break;
541 case '/':
542 if (is_just_unknown(e) || is_just_unknown(f))
543 e = unknown_expr();
544 else
545 e = scalarvect (((unsigned long)reloc_value(e)) /
546 ((unsigned long)reloc_value(f)));
547 break;
548 case '%':
549 if (is_just_unknown(e) || is_just_unknown(f))
550 e = unknown_expr();
551 else
552 e = scalarvect (((unsigned long)reloc_value(e)) %
553 ((unsigned long)reloc_value(f)));
554 break;
555 case TOKEN_SDIV:
556 if (is_just_unknown(e) || is_just_unknown(f))
557 e = unknown_expr();
558 else
559 e = scalarvect (((signed long)reloc_value(e)) /
560 ((signed long)reloc_value(f)));
561 break;
562 case TOKEN_SMOD:
563 if (is_just_unknown(e) || is_just_unknown(f))
564 e = unknown_expr();
565 else
566 e = scalarvect (((signed long)reloc_value(e)) %
567 ((signed long)reloc_value(f)));
568 break;
569 }
570 }
571 return e;
572}
573
574static expr *expr6(int critical) {
575 long type;
576 expr *e;
577 long label_seg, label_ofs;
578
579 if (i == '-') {
580 i = scan(scpriv, tokval);
581 e = expr6(critical);
582 if (!e)
583 return NULL;
584 return scalar_mult (e, -1L, FALSE);
585 } else if (i == '+') {
586 i = scan(scpriv, tokval);
587 return expr6(critical);
588 } else if (i == '~') {
589 i = scan(scpriv, tokval);
590 e = expr6(critical);
591 if (!e)
592 return NULL;
593 if (is_just_unknown(e))
594 return unknown_expr();
595 else if (!is_simple(e)) {
596 error(ERR_NONFATAL, "`~' operator may only be applied to"
597 " scalar values");
598 return NULL;
599 }
600 return scalarvect(~reloc_value(e));
601 } else if (i == TOKEN_SEG) {
602 i = scan(scpriv, tokval);
603 e = expr6(critical);
604 if (!e)
605 return NULL;
606 e = segment_part(e);
607 if (is_unknown(e) && critical) {
608 error(ERR_NONFATAL, "unable to determine segment base");
609 return NULL;
610 }
611 return e;
612 } else if (i == '(') {
613 i = scan(scpriv, tokval);
614 e = bexpr(critical);
615 if (!e)
616 return NULL;
617 if (i != ')') {
618 error(ERR_NONFATAL, "expecting `)'");
619 return NULL;
620 }
621 i = scan(scpriv, tokval);
622 return e;
623 } else if (i == TOKEN_NUM || i == TOKEN_REG || i == TOKEN_ID ||
624 i == TOKEN_HERE || i == TOKEN_BASE) {
625 begintemp();
626 switch (i) {
627 case TOKEN_NUM:
628 addtotemp(EXPR_SIMPLE, tokval->t_integer);
629 break;
630 case TOKEN_REG:
631 addtotemp(tokval->t_integer, 1L);
632 if (hint && hint->type == EAH_NOHINT)
633 hint->base = tokval->t_integer, hint->type = EAH_MAKEBASE;
634 break;
635 case TOKEN_ID:
636 case TOKEN_HERE:
637 case TOKEN_BASE:
638 /*
639 * If "label" begins with "%", this indicates that no
640 * symbol, Here or Base references are valid because we
641 * are in preprocess-only mode.
642 */
643 if (*label == '%') {
644 error(ERR_NONFATAL,
645 "%s not supported in preprocess-only mode",
646 (i == TOKEN_ID ? "symbol references" :
647 i == TOKEN_HERE ? "`$'" : "`$$'"));
648 addtotemp(EXPR_UNKNOWN, 1L);
649 break;
650 }
651
652 /*
653 * Since the whole line is parsed before the label it
654 * defines is given to the label manager, we have
655 * problems with lines such as
656 *
657 * end: TIMES 512-(end-start) DB 0
658 *
659 * where `end' is not known on pass one, despite not
660 * really being a forward reference, and due to
661 * criticality it is _needed_. Hence we check our label
662 * against the currently defined one, and do our own
663 * resolution of it if we have to.
664 */
665 type = EXPR_SIMPLE; /* might get overridden by UNKNOWN */
666 if (i == TOKEN_BASE) {
667 label_seg = seg;
668 label_ofs = 0;
669 } else if (i == TOKEN_HERE || !strcmp(tokval->t_charptr, label)) {
670 label_seg = seg;
671 label_ofs = ofs;
672 } else if (!labelfunc(tokval->t_charptr,&label_seg,&label_ofs)) {
673 if (critical == 2) {
674 error (ERR_NONFATAL, "symbol `%s' undefined",
675 tokval->t_charptr);
676 return NULL;
677 } else if (critical == 1) {
678 error (ERR_NONFATAL, "symbol `%s' not defined before use",
679 tokval->t_charptr);
680 return NULL;
681 } else {
682 if (forward)
683 *forward = TRUE;
684 type = EXPR_UNKNOWN;
685 label_seg = NO_SEG;
686 label_ofs = 1;
687 }
688 }
689 addtotemp(type, label_ofs);
690 if (label_seg!=NO_SEG)
691 addtotemp(EXPR_SEGBASE + label_seg, 1L);
692 break;
693 }
694 i = scan(scpriv, tokval);
695 return finishtemp();
696 } else {
697 error(ERR_NONFATAL, "expression syntax error");
698 return NULL;
699 }
700}
701
702void eval_global_info (struct ofmt *output, lfunc lookup_label) {
703 outfmt = output;
704 labelfunc = lookup_label;
705}
706
707void eval_info (char *labelname, long segment, long offset) {
708 if (label != special_empty_string)
709 nasm_free (label);
710 if (labelname)
711 label = nasm_strdup(labelname);
712 else {
713 label = special_empty_string;
714 seg = segment;
715 ofs = offset;
716 }
717}
718
719expr *evaluate (scanner sc, void *scprivate, struct tokenval *tv,
720 int *fwref, int critical, efunc report_error,
721 struct eval_hints *hints) {
722 expr *e;
723 expr *f = NULL;
724
725 hint = hints;
726 if (hint)
727 hint->type = EAH_NOHINT;
728
729 if (critical & 0x10) {
730 critical &= ~0x10;
731 bexpr = rexp0;
732 } else
733 bexpr = expr0;
734
735 scan = sc;
736 scpriv = scprivate;
737 tokval = tv;
738 error = report_error;
739 forward = fwref;
740
741 if (tokval->t_type == TOKEN_INVALID)
742 i = scan(scpriv, tokval);
743 else
744 i = tokval->t_type;
745
746 while (ntempexprs) /* initialise temporary storage */
747 nasm_free (tempexprs[--ntempexprs]);
748
749 e = bexpr (critical);
750 if (!e)
751 return NULL;
752
753 if (i == TOKEN_WRT) {
754 i = scan(scpriv, tokval); /* eat the WRT */
755 f = expr6 (critical);
756 if (!f)
757 return NULL;
758 }
759 e = scalar_mult (e, 1L, FALSE); /* strip far-absolute segment part */
760 if (f) {
761 expr *g;
762 if (is_just_unknown(f))
763 g = unknown_expr();
764 else {
765 long value;
766 begintemp();
767 if (!is_reloc(f)) {
768 error(ERR_NONFATAL, "invalid right-hand operand to WRT");
769 return NULL;
770 }
771 value = reloc_seg(f);
772 if (value == NO_SEG)
773 value = reloc_value(f) | SEG_ABS;
774 else if (!(value & SEG_ABS) && !(value % 2) && critical) {
775 error(ERR_NONFATAL, "invalid right-hand operand to WRT");
776 return NULL;
777 }
778 addtotemp(EXPR_WRT, value);
779 g = finishtemp();
780 }
781 e = add_vectors (e, g);
782 }
783 return e;
784}