]>
Commit | Line | Data |
---|---|---|
14c7c974 A |
1 | /* |
2 | * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
4f6e3300 A |
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. | |
14c7c974 A |
13 | * |
14 | * The Original Code and all software distributed under the License are | |
4f6e3300 | 15 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER |
14c7c974 A |
16 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
17 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
4f6e3300 A |
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. | |
14c7c974 A |
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 | ||
44 | static expr **tempexprs = NULL; | |
45 | static int ntempexprs, tempexprs_size = 0; | |
46 | #define TEMPEXPRS_DELTA 128 | |
47 | ||
48 | static expr *tempexpr; | |
49 | static int ntempexpr, tempexpr_size; | |
50 | #define TEMPEXPR_DELTA 8 | |
51 | ||
52 | static scanner scan; | |
53 | static void *scpriv; | |
54 | static struct tokenval *tokval; | |
55 | static efunc error; | |
56 | static int i; | |
57 | static int seg, ofs; | |
58 | static char *label = NULL, special_empty_string[] = ""; | |
59 | static lfunc labelfunc; | |
60 | static struct ofmt *outfmt; | |
61 | static int *forward; | |
62 | ||
63 | static struct eval_hints *hint; | |
64 | ||
65 | /* | |
66 | * Construct a temporary expression. | |
67 | */ | |
68 | static void begintemp(void) { | |
69 | tempexpr = NULL; | |
70 | tempexpr_size = ntempexpr = 0; | |
71 | } | |
72 | ||
73 | static 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 | ||
83 | static 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 | */ | |
98 | static 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 | */ | |
151 | static 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 | ||
166 | static expr *scalarvect (long scalar) { | |
167 | begintemp(); | |
168 | addtotemp(EXPR_SIMPLE, scalar); | |
169 | return finishtemp(); | |
170 | } | |
171 | ||
172 | static 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 | */ | |
183 | static 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 | ||
247 | static expr *rexp0(int), *rexp1(int), *rexp2(int), *rexp3(int); | |
248 | ||
249 | static expr *expr0(int), *expr1(int), *expr2(int), *expr3(int); | |
250 | static expr *expr4(int), *expr5(int), *expr6(int); | |
251 | ||
252 | static expr *(*bexpr)(int); | |
253 | ||
254 | static 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 | ||
278 | static 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 | ||
302 | static 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 | ||
326 | static 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 | ||
377 | static 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 | ||
401 | static 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 | ||
425 | static 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 | ||
449 | static 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 | ||
480 | static 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 | ||
504 | static 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 | ||
574 | static 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 | ||
702 | void eval_global_info (struct ofmt *output, lfunc lookup_label) { | |
703 | outfmt = output; | |
704 | labelfunc = lookup_label; | |
705 | } | |
706 | ||
707 | void 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 | ||
719 | expr *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 | } |