Commit | Line | Data |
---|---|---|
ee3d3814 C |
1 | /* expr.c -operands, expressions- |
2 | Copyright (C) 1987 Free Software Foundation, Inc. | |
3 | ||
4 | This file is part of GAS, the GNU Assembler. | |
5 | ||
6 | GAS is free software; you can redistribute it and/or modify | |
7 | it under the terms of the GNU General Public License as published by | |
8 | the Free Software Foundation; either version 1, or (at your option) | |
9 | any later version. | |
10 | ||
11 | GAS is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
17 | along with GAS; see the file COPYING. If not, write to | |
18 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
19 | ||
20 | /* | |
21 | * This is really a branch office of as-read.c. I split it out to clearly | |
22 | * distinguish the world of expressions from the world of statements. | |
23 | * (It also gives smaller files to re-compile.) | |
24 | * Here, "operand"s are of expressions, not instructions. | |
25 | */ | |
26 | ||
27 | #include <ctype.h> | |
28 | #include "as.h" | |
29 | #include "flonum.h" | |
30 | #include "read.h" | |
31 | #include "struc-symbol.h" | |
32 | #include "expr.h" | |
33 | #include "obstack.h" | |
34 | #include "symbols.h" | |
35 | ||
36 | static void clean_up_expression(); /* Internal. */ | |
37 | extern const char EXP_CHARS[]; /* JF hide MD floating pt stuff all the same place */ | |
38 | extern const char FLT_CHARS[]; | |
39 | ||
40 | #ifdef SUN_ASM_SYNTAX | |
41 | extern int local_label_defined[]; | |
42 | #endif | |
43 | ||
44 | /* | |
45 | * Build any floating-point literal here. | |
46 | * Also build any bignum literal here. | |
47 | */ | |
48 | ||
49 | /* LITTLENUM_TYPE generic_buffer [6]; /* JF this is a hack */ | |
50 | /* Seems atof_machine can backscan through generic_bignum and hit whatever | |
51 | happens to be loaded before it in memory. And its way too complicated | |
52 | for me to fix right. Thus a hack. JF: Just make generic_bignum bigger, | |
53 | and never write into the early words, thus they'll always be zero. | |
54 | I hate Dean's floating-point code. Bleh. | |
55 | */ | |
56 | LITTLENUM_TYPE generic_bignum [SIZE_OF_LARGE_NUMBER+6]; | |
57 | FLONUM_TYPE generic_floating_point_number = | |
58 | { | |
59 | & generic_bignum [6], /* low (JF: Was 0) */ | |
60 | & generic_bignum [SIZE_OF_LARGE_NUMBER+6 - 1], /* high JF: (added +6) */ | |
61 | 0, /* leader */ | |
62 | 0, /* exponent */ | |
63 | 0 /* sign */ | |
64 | }; | |
65 | /* If nonzero, we've been asked to assemble nan, +inf or -inf */ | |
66 | int generic_floating_point_magic; | |
67 | \f | |
68 | /* | |
69 | * Summary of operand(). | |
70 | * | |
71 | * in: Input_line_pointer points to 1st char of operand, which may | |
72 | * be a space. | |
73 | * | |
74 | * out: A expressionS. X_seg determines how to understand the rest of the | |
75 | * expressionS. | |
76 | * The operand may have been empty: in this case X_seg == SEG_NONE. | |
77 | * Input_line_pointer -> (next non-blank) char after operand. | |
78 | * | |
79 | */ | |
80 | \f | |
81 | static segT | |
82 | operand (expressionP) | |
83 | register expressionS * expressionP; | |
84 | { | |
85 | register char c; | |
86 | register char *name; /* points to name of symbol */ | |
87 | register struct symbol * symbolP; /* Points to symbol */ | |
88 | ||
89 | extern char hex_value[]; /* In hex_value.c */ | |
90 | char *local_label_name(); | |
91 | ||
92 | SKIP_WHITESPACE(); /* Leading whitespace is part of operand. */ | |
93 | c = * input_line_pointer ++; /* Input_line_pointer -> past char in c. */ | |
94 | if (isdigit(c)) | |
95 | { | |
96 | register valueT number; /* offset or (absolute) value */ | |
97 | register short int digit; /* value of next digit in current radix */ | |
98 | /* invented for humans only, hope */ | |
99 | /* optimising compiler flushes it! */ | |
100 | register short int radix; /* 8, 10 or 16 */ | |
101 | /* 0 means we saw start of a floating- */ | |
102 | /* point constant. */ | |
103 | register short int maxdig;/* Highest permitted digit value. */ | |
104 | register int too_many_digits; /* If we see >= this number of */ | |
105 | /* digits, assume it is a bignum. */ | |
106 | register char * digit_2; /* -> 2nd digit of number. */ | |
107 | int small; /* TRUE if fits in 32 bits. */ | |
108 | ||
109 | if (c=='0') | |
110 | { /* non-decimal radix */ | |
111 | if ((c = * input_line_pointer ++)=='x' || c=='X') | |
112 | { | |
113 | c = * input_line_pointer ++; /* read past "0x" or "0X" */ | |
114 | maxdig = radix = 16; | |
115 | too_many_digits = 9; | |
116 | } | |
117 | else | |
118 | { | |
119 | /* If it says '0f' and the line ends or it DOESN'T look like | |
120 | a floating point #, its a local label ref. DTRT */ | |
121 | if(c=='f' && (! *input_line_pointer || | |
122 | (!index("+-.0123456789",*input_line_pointer) && | |
123 | !index(EXP_CHARS,*input_line_pointer)))) | |
124 | { | |
125 | maxdig = radix = 10; | |
126 | too_many_digits = 11; | |
127 | c='0'; | |
128 | input_line_pointer-=2; | |
129 | } | |
130 | else if (c && index (FLT_CHARS,c)) | |
131 | { | |
132 | radix = 0; /* Start of floating-point constant. */ | |
133 | /* input_line_pointer -> 1st char of number. */ | |
134 | expressionP -> X_add_number = - (isupper(c) ? tolower(c) : c); | |
135 | } | |
136 | else | |
137 | { /* By elimination, assume octal radix. */ | |
138 | radix = 8; | |
139 | maxdig = 10; /* Un*x sux. Compatibility. */ | |
140 | too_many_digits = 11; | |
141 | } | |
142 | } | |
143 | /* c == char after "0" or "0x" or "0X" or "0e" etc.*/ | |
144 | } | |
145 | else | |
146 | { | |
147 | maxdig = radix = 10; | |
148 | too_many_digits = 11; | |
149 | } | |
150 | if (radix) | |
151 | { /* Fixed-point integer constant. */ | |
152 | /* May be bignum, or may fit in 32 bits. */ | |
153 | /* | |
154 | * Most numbers fit into 32 bits, and we want this case to be fast. | |
155 | * So we pretend it will fit into 32 bits. If, after making up a 32 | |
156 | * bit number, we realise that we have scanned more digits than | |
157 | * comfortably fit into 32 bits, we re-scan the digits coding | |
158 | * them into a bignum. For decimal and octal numbers we are conservative: some | |
159 | * numbers may be assumed bignums when in fact they do fit into 32 bits. | |
160 | * Numbers of any radix can have excess leading zeros: we strive | |
161 | * to recognise this and cast them back into 32 bits. | |
162 | * We must check that the bignum really is more than 32 | |
163 | * bits, and change it back to a 32-bit number if it fits. | |
164 | * The number we are looking for is expected to be positive, but | |
165 | * if it fits into 32 bits as an unsigned number, we let it be a 32-bit | |
166 | * number. The cavalier approach is for speed in ordinary cases. | |
167 | */ | |
168 | digit_2 = input_line_pointer; | |
169 | for (number=0; (digit=hex_value[c])<maxdig; c = * input_line_pointer ++) | |
170 | { | |
171 | number = number * radix + digit; | |
172 | } | |
173 | /* C contains character after number. */ | |
174 | /* Input_line_pointer -> char after C. */ | |
175 | small = input_line_pointer - digit_2 < too_many_digits; | |
176 | if ( ! small) | |
177 | { | |
178 | /* | |
179 | * We saw a lot of digits. Manufacture a bignum the hard way. | |
180 | */ | |
181 | LITTLENUM_TYPE * leader; /* -> high order littlenum of the bignum. */ | |
182 | LITTLENUM_TYPE * pointer; /* -> littlenum we are frobbing now. */ | |
183 | long int carry; | |
184 | ||
185 | leader = generic_bignum; | |
186 | generic_bignum [0] = 0; | |
187 | generic_bignum [1] = 0; | |
188 | /* We could just use digit_2, but lets be mnemonic. */ | |
189 | input_line_pointer = -- digit_2; /* -> 1st digit. */ | |
190 | c = *input_line_pointer ++; | |
191 | for (; (carry = hex_value [c]) < maxdig; c = * input_line_pointer ++) | |
192 | { | |
193 | for (pointer = generic_bignum; | |
194 | pointer <= leader; | |
195 | pointer ++) | |
196 | { | |
197 | long int work; | |
198 | ||
199 | work = carry + radix * * pointer; | |
200 | * pointer = work & LITTLENUM_MASK; | |
201 | carry = work >> LITTLENUM_NUMBER_OF_BITS; | |
202 | } | |
203 | if (carry) | |
204 | { | |
205 | if (leader < generic_bignum + SIZE_OF_LARGE_NUMBER - 1) | |
206 | { /* Room to grow a longer bignum. */ | |
207 | * ++ leader = carry; | |
208 | } | |
209 | } | |
210 | } | |
211 | /* Again, C is char after number, */ | |
212 | /* input_line_pointer -> after C. */ | |
213 | know( BITS_PER_INT == 32 ); | |
214 | know( LITTLENUM_NUMBER_OF_BITS == 16 ); | |
215 | /* Hence the constant "2" in the next line. */ | |
216 | if (leader < generic_bignum + 2) | |
217 | { /* Will fit into 32 bits. */ | |
218 | number = | |
219 | ( (generic_bignum [1] & LITTLENUM_MASK) << LITTLENUM_NUMBER_OF_BITS ) | |
220 | | (generic_bignum [0] & LITTLENUM_MASK); | |
221 | small = TRUE; | |
222 | } | |
223 | else | |
224 | { | |
225 | number = leader - generic_bignum + 1; /* Number of littlenums in the bignum. */ | |
226 | } | |
227 | } | |
228 | if (small) | |
229 | { | |
230 | /* | |
231 | * Here with number, in correct radix. c is the next char. | |
232 | * Note that unlike Un*x, we allow "011f" "0x9f" to | |
233 | * both mean the same as the (conventional) "9f". This is simply easier | |
234 | * than checking for strict canonical form. Syntax sux! | |
235 | */ | |
236 | if (number<10) | |
237 | { | |
238 | #ifdef SUN_ASM_SYNTAX | |
239 | if (c=='b' || (c=='$' && local_label_defined[number])) | |
240 | #else | |
241 | if (c=='b') | |
242 | #endif | |
243 | { | |
244 | /* | |
245 | * Backward ref to local label. | |
246 | * Because it is backward, expect it to be DEFINED. | |
247 | */ | |
248 | /* | |
249 | * Construct a local label. | |
250 | */ | |
251 | name = local_label_name ((int)number, 0); | |
252 | if ( (symbolP = symbol_table_lookup(name)) /* seen before */ | |
253 | && (symbolP -> sy_type & N_TYPE) != N_UNDF /* symbol is defined: OK */ | |
254 | ) | |
255 | { /* Expected path: symbol defined. */ | |
256 | /* Local labels are never absolute. Don't waste time checking absoluteness. */ | |
257 | know( (symbolP -> sy_type & N_TYPE) == N_DATA | |
258 | || (symbolP -> sy_type & N_TYPE) == N_TEXT ); | |
259 | expressionP -> X_add_symbol = symbolP; | |
260 | expressionP -> X_add_number = 0; | |
261 | expressionP -> X_seg = N_TYPE_seg [symbolP -> sy_type]; | |
262 | } | |
263 | else | |
264 | { /* Either not seen or not defined. */ | |
265 | as_warn( "Backw. ref to unknown label \"%d:\", 0 assumed.", | |
266 | number | |
267 | ); | |
268 | expressionP -> X_add_number = 0; | |
269 | expressionP -> X_seg = SEG_ABSOLUTE; | |
270 | } | |
271 | } | |
272 | else | |
273 | { | |
274 | #ifdef SUN_ASM_SYNTAX | |
275 | if (c=='f' || (c=='$' && !local_label_defined[number])) | |
276 | #else | |
277 | if (c=='f') | |
278 | #endif | |
279 | { | |
280 | /* | |
281 | * Forward reference. Expect symbol to be undefined or | |
282 | * unknown. Undefined: seen it before. Unknown: never seen | |
283 | * it in this pass. | |
284 | * Construct a local label name, then an undefined symbol. | |
285 | * Don't create a XSEG frag for it: caller may do that. | |
286 | * Just return it as never seen before. | |
287 | */ | |
288 | name = local_label_name ((int)number, 1); | |
289 | if ( symbolP = symbol_table_lookup( name )) | |
290 | { | |
291 | /* We have no need to check symbol properties. */ | |
292 | know( (symbolP -> sy_type & N_TYPE) == N_UNDF | |
293 | || (symbolP -> sy_type & N_TYPE) == N_DATA | |
294 | || (symbolP -> sy_type & N_TYPE) == N_TEXT); | |
295 | } | |
296 | else | |
297 | { | |
298 | symbolP = symbol_new (name, N_UNDF, 0,0,0, & zero_address_frag); | |
299 | symbol_table_insert (symbolP); | |
300 | } | |
301 | expressionP -> X_add_symbol = symbolP; | |
302 | expressionP -> X_seg = SEG_UNKNOWN; | |
303 | expressionP -> X_subtract_symbol = NULL; | |
304 | expressionP -> X_add_number = 0; | |
305 | } | |
306 | else | |
307 | { /* Really a number, not a local label. */ | |
308 | expressionP -> X_add_number = number; | |
309 | expressionP -> X_seg = SEG_ABSOLUTE; | |
310 | input_line_pointer --; /* Restore following character. */ | |
311 | } /* if (c=='f') */ | |
312 | } /* if (c=='b') */ | |
313 | } | |
314 | else | |
315 | { /* Really a number. */ | |
316 | expressionP -> X_add_number = number; | |
317 | expressionP -> X_seg = SEG_ABSOLUTE; | |
318 | input_line_pointer --; /* Restore following character. */ | |
319 | } /* if (number<10) */ | |
320 | } | |
321 | else | |
322 | { | |
323 | expressionP -> X_add_number = number; | |
324 | expressionP -> X_seg = SEG_BIG; | |
325 | input_line_pointer --; /* -> char following number. */ | |
326 | } /* if (small) */ | |
327 | } /* (If integer constant) */ | |
328 | else | |
329 | { /* input_line_pointer -> */ | |
330 | /* floating-point constant. */ | |
331 | int error_code; | |
332 | ||
333 | error_code = atof_generic | |
334 | (& input_line_pointer, ".", EXP_CHARS, | |
335 | & generic_floating_point_number); | |
336 | ||
337 | if (error_code) | |
338 | { | |
339 | if (error_code == ERROR_EXPONENT_OVERFLOW) | |
340 | { | |
341 | as_warn( "Bad floating-point constant: exponent overflow, probably assembling junk" ); | |
342 | } | |
343 | else | |
344 | { | |
345 | as_warn( "Bad floating-point constant: unknown error code=%d.", error_code); | |
346 | } | |
347 | } | |
348 | expressionP -> X_seg = SEG_BIG; | |
349 | /* input_line_pointer -> just after constant, */ | |
350 | /* which may point to whitespace. */ | |
351 | know( expressionP -> X_add_number < 0 ); /* < 0 means "floating point". */ | |
352 | } /* if (not floating-point constant) */ | |
353 | } | |
354 | else if(c=='.' && !is_part_of_name(*input_line_pointer)) { | |
355 | extern struct obstack frags; | |
356 | ||
357 | /* | |
358 | JF: '.' is pseudo symbol with value of current location in current | |
359 | segment. . . | |
360 | */ | |
361 | symbolP = symbol_new("L0\001", | |
362 | (unsigned char)(seg_N_TYPE[(int)now_seg]), | |
363 | 0, | |
364 | 0, | |
365 | (valueT)(obstack_next_free(&frags)-frag_now->fr_literal), | |
366 | frag_now); | |
367 | expressionP->X_add_number=0; | |
368 | expressionP->X_add_symbol=symbolP; | |
369 | expressionP->X_seg = now_seg; | |
370 | ||
371 | } else if ( is_name_beginner(c) ) /* here if did not begin with a digit */ | |
372 | { | |
373 | /* | |
374 | * Identifier begins here. | |
375 | * This is kludged for speed, so code is repeated. | |
376 | */ | |
377 | name = -- input_line_pointer; | |
378 | c = get_symbol_end(); | |
379 | symbolP = symbol_table_lookup(name); | |
380 | if (symbolP) | |
381 | { | |
382 | /* | |
383 | * If we have an absolute symbol, then we know it's value now. | |
384 | */ | |
385 | register segT seg; | |
386 | ||
387 | seg = N_TYPE_seg [(int) symbolP -> sy_type & N_TYPE]; | |
388 | if ((expressionP -> X_seg = seg) == SEG_ABSOLUTE ) | |
389 | { | |
390 | expressionP -> X_add_number = symbolP -> sy_value; | |
391 | } | |
392 | else | |
393 | { | |
394 | expressionP -> X_add_number = 0; | |
395 | expressionP -> X_add_symbol = symbolP; | |
396 | } | |
397 | } | |
398 | else | |
399 | { | |
400 | expressionP -> X_add_symbol | |
401 | = symbolP | |
402 | = symbol_new (name, N_UNDF, 0,0,0, & zero_address_frag); | |
403 | ||
404 | expressionP -> X_add_number = 0; | |
405 | expressionP -> X_seg = SEG_UNKNOWN; | |
406 | symbol_table_insert (symbolP); | |
407 | } | |
408 | * input_line_pointer = c; | |
409 | expressionP -> X_subtract_symbol = NULL; | |
410 | } | |
411 | else if (c=='(')/* didn't begin with digit & not a name */ | |
412 | { | |
413 | (void)expression( expressionP ); | |
414 | /* Expression() will pass trailing whitespace */ | |
415 | if ( * input_line_pointer ++ != ')' ) | |
416 | { | |
417 | as_warn( "Missing ')' assumed"); | |
418 | input_line_pointer --; | |
419 | } | |
420 | /* here with input_line_pointer -> char after "(...)" */ | |
421 | } | |
422 | else if ( c=='~' || c=='-' ) | |
423 | { /* unary operator: hope for SEG_ABSOLUTE */ | |
424 | switch(operand (expressionP)) { | |
425 | case SEG_ABSOLUTE: | |
426 | /* input_line_pointer -> char after operand */ | |
427 | if ( c=='-' ) | |
428 | { | |
429 | expressionP -> X_add_number = - expressionP -> X_add_number; | |
430 | /* | |
431 | * Notice: '-' may overflow: no warning is given. This is compatible | |
432 | * with other people's assemblers. Sigh. | |
433 | */ | |
434 | } | |
435 | else | |
436 | { | |
437 | expressionP -> X_add_number = ~ expressionP -> X_add_number; | |
438 | } | |
439 | break; | |
440 | ||
441 | case SEG_TEXT: | |
442 | case SEG_DATA: | |
443 | case SEG_BSS: | |
444 | case SEG_PASS1: | |
445 | case SEG_UNKNOWN: | |
446 | if(c=='-') { /* JF I hope this hack works */ | |
447 | expressionP->X_subtract_symbol=expressionP->X_add_symbol; | |
448 | expressionP->X_add_symbol=0; | |
449 | expressionP->X_seg=SEG_DIFFERENCE; | |
450 | break; | |
451 | } | |
452 | default: /* unary on non-absolute is unsuported */ | |
453 | as_warn("Unary operator %c ignored because bad operand follows", c); | |
454 | break; | |
455 | /* Expression undisturbed from operand(). */ | |
456 | } | |
457 | } | |
458 | else if (c=='\'') | |
459 | { | |
460 | /* | |
461 | * Warning: to conform to other people's assemblers NO ESCAPEMENT is permitted | |
462 | * for a single quote. The next character, parity errors and all, is taken | |
463 | * as the value of the operand. VERY KINKY. | |
464 | */ | |
465 | expressionP -> X_add_number = * input_line_pointer ++; | |
466 | expressionP -> X_seg = SEG_ABSOLUTE; | |
467 | } | |
468 | else | |
469 | { | |
470 | /* can't imagine any other kind of operand */ | |
471 | expressionP -> X_seg = SEG_NONE; | |
472 | input_line_pointer --; | |
473 | } | |
474 | /* | |
475 | * It is more 'efficient' to clean up the expressions when they are created. | |
476 | * Doing it here saves lines of code. | |
477 | */ | |
478 | clean_up_expression (expressionP); | |
479 | SKIP_WHITESPACE(); /* -> 1st char after operand. */ | |
480 | know( * input_line_pointer != ' ' ); | |
481 | return (expressionP -> X_seg); | |
482 | } /* operand */ | |
483 | \f | |
484 | /* Internal. Simplify a struct expression for use by expr() */ | |
485 | ||
486 | /* | |
487 | * In: address of a expressionS. | |
488 | * The X_seg field of the expressionS may only take certain values. | |
489 | * Now, we permit SEG_PASS1 to make code smaller & faster. | |
490 | * Elsewise we waste time special-case testing. Sigh. Ditto SEG_NONE. | |
491 | * Out: expressionS may have been modified: | |
492 | * 'foo-foo' symbol references cancelled to 0, | |
493 | * which changes X_seg from SEG_DIFFERENCE to SEG_ABSOLUTE; | |
494 | * Unused fields zeroed to help expr(). | |
495 | */ | |
496 | ||
497 | static void | |
498 | clean_up_expression (expressionP) | |
499 | register expressionS * expressionP; | |
500 | { | |
501 | switch (expressionP -> X_seg) | |
502 | { | |
503 | case SEG_NONE: | |
504 | case SEG_PASS1: | |
505 | expressionP -> X_add_symbol = NULL; | |
506 | expressionP -> X_subtract_symbol = NULL; | |
507 | expressionP -> X_add_number = 0; | |
508 | break; | |
509 | ||
510 | case SEG_BIG: | |
511 | case SEG_ABSOLUTE: | |
512 | expressionP -> X_subtract_symbol = NULL; | |
513 | expressionP -> X_add_symbol = NULL; | |
514 | break; | |
515 | ||
516 | case SEG_TEXT: | |
517 | case SEG_DATA: | |
518 | case SEG_BSS: | |
519 | case SEG_UNKNOWN: | |
520 | expressionP -> X_subtract_symbol = NULL; | |
521 | break; | |
522 | ||
523 | case SEG_DIFFERENCE: | |
524 | /* | |
525 | * It does not hurt to 'cancel' NULL==NULL | |
526 | * when comparing symbols for 'eq'ness. | |
527 | * It is faster to re-cancel them to NULL | |
528 | * than to check for this special case. | |
529 | */ | |
530 | if (expressionP -> X_subtract_symbol == expressionP -> X_add_symbol | |
531 | || ( expressionP->X_subtract_symbol | |
532 | && expressionP->X_add_symbol | |
533 | && expressionP->X_subtract_symbol->sy_frag==expressionP->X_add_symbol->sy_frag | |
534 | && expressionP->X_subtract_symbol->sy_value==expressionP->X_add_symbol->sy_value)) | |
535 | { | |
536 | expressionP -> X_subtract_symbol = NULL; | |
537 | expressionP -> X_add_symbol = NULL; | |
538 | expressionP -> X_seg = SEG_ABSOLUTE; | |
539 | } | |
540 | break; | |
541 | ||
542 | default: | |
543 | BAD_CASE( expressionP -> X_seg); | |
544 | break; | |
545 | } | |
546 | } | |
547 | \f | |
548 | /* | |
549 | * expr_part () | |
550 | * | |
551 | * Internal. Made a function because this code is used in 2 places. | |
552 | * Generate error or correct X_?????_symbol of expressionS. | |
553 | */ | |
554 | ||
555 | /* | |
556 | * symbol_1 += symbol_2 ... well ... sort of. | |
557 | */ | |
558 | ||
559 | static segT | |
560 | expr_part (symbol_1_PP, symbol_2_P) | |
561 | struct symbol ** symbol_1_PP; | |
562 | struct symbol * symbol_2_P; | |
563 | { | |
564 | segT return_value; | |
565 | ||
566 | know( (* symbol_1_PP) == NULL | |
567 | || ((* symbol_1_PP) -> sy_type & N_TYPE) == N_TEXT | |
568 | || ((* symbol_1_PP) -> sy_type & N_TYPE) == N_DATA | |
569 | || ((* symbol_1_PP) -> sy_type & N_TYPE) == N_BSS | |
570 | || ((* symbol_1_PP) -> sy_type & N_TYPE) == N_UNDF | |
571 | ); | |
572 | know( symbol_2_P == NULL | |
573 | || (symbol_2_P -> sy_type & N_TYPE) == N_TEXT | |
574 | || (symbol_2_P -> sy_type & N_TYPE) == N_DATA | |
575 | || (symbol_2_P -> sy_type & N_TYPE) == N_BSS | |
576 | || (symbol_2_P -> sy_type & N_TYPE) == N_UNDF | |
577 | ); | |
578 | if (* symbol_1_PP) | |
579 | { | |
580 | if (((* symbol_1_PP) -> sy_type & N_TYPE) == N_UNDF) | |
581 | { | |
582 | if (symbol_2_P) | |
583 | { | |
584 | return_value = SEG_PASS1; | |
585 | * symbol_1_PP = NULL; | |
586 | } | |
587 | else | |
588 | { | |
589 | know( ((* symbol_1_PP) -> sy_type & N_TYPE) == N_UNDF) | |
590 | return_value = SEG_UNKNOWN; | |
591 | } | |
592 | } | |
593 | else | |
594 | { | |
595 | if (symbol_2_P) | |
596 | { | |
597 | if ((symbol_2_P -> sy_type & N_TYPE) == N_UNDF) | |
598 | { | |
599 | * symbol_1_PP = NULL; | |
600 | return_value = SEG_PASS1; | |
601 | } | |
602 | else | |
603 | { | |
604 | /* {seg1} - {seg2} */ | |
605 | as_warn( "Expression too complex, 2 symbols forgotten: \"%s\" \"%s\"", | |
606 | (* symbol_1_PP) -> sy_name, symbol_2_P -> sy_name ); | |
607 | * symbol_1_PP = NULL; | |
608 | return_value = SEG_ABSOLUTE; | |
609 | } | |
610 | } | |
611 | else | |
612 | { | |
613 | return_value = N_TYPE_seg [(* symbol_1_PP) -> sy_type & N_TYPE]; | |
614 | } | |
615 | } | |
616 | } | |
617 | else | |
618 | { /* (* symbol_1_PP) == NULL */ | |
619 | if (symbol_2_P) | |
620 | { | |
621 | * symbol_1_PP = symbol_2_P; | |
622 | return_value = N_TYPE_seg [(symbol_2_P) -> sy_type & N_TYPE]; | |
623 | } | |
624 | else | |
625 | { | |
626 | * symbol_1_PP = NULL; | |
627 | return_value = SEG_ABSOLUTE; | |
628 | } | |
629 | } | |
630 | know( return_value == SEG_ABSOLUTE | |
631 | || return_value == SEG_TEXT | |
632 | || return_value == SEG_DATA | |
633 | || return_value == SEG_BSS | |
634 | || return_value == SEG_UNKNOWN | |
635 | || return_value == SEG_PASS1 | |
636 | ); | |
637 | know( (* symbol_1_PP) == NULL | |
638 | || ((* symbol_1_PP) -> sy_type & N_TYPE) == seg_N_TYPE [(int) return_value] ); | |
639 | return (return_value); | |
640 | } /* expr_part() */ | |
641 | \f | |
642 | /* Expression parser. */ | |
643 | ||
644 | /* | |
645 | * We allow an empty expression, and just assume (absolute,0) silently. | |
646 | * Unary operators and parenthetical expressions are treated as operands. | |
647 | * As usual, Q==quantity==operand, O==operator, X==expression mnemonics. | |
648 | * | |
649 | * We used to do a aho/ullman shift-reduce parser, but the logic got so | |
650 | * warped that I flushed it and wrote a recursive-descent parser instead. | |
651 | * Now things are stable, would anybody like to write a fast parser? | |
652 | * Most expressions are either register (which does not even reach here) | |
653 | * or 1 symbol. Then "symbol+constant" and "symbol-symbol" are common. | |
654 | * So I guess it doesn't really matter how inefficient more complex expressions | |
655 | * are parsed. | |
656 | * | |
657 | * After expr(RANK,resultP) input_line_pointer -> operator of rank <= RANK. | |
658 | * Also, we have consumed any leading or trailing spaces (operand does that) | |
659 | * and done all intervening operators. | |
660 | */ | |
661 | ||
662 | typedef enum | |
663 | { | |
664 | O_illegal, /* (0) what we get for illegal op */ | |
665 | ||
666 | O_multiply, /* (1) * */ | |
667 | O_divide, /* (2) / */ | |
668 | O_modulus, /* (3) % */ | |
669 | O_left_shift, /* (4) < */ | |
670 | O_right_shift, /* (5) > */ | |
671 | O_bit_inclusive_or, /* (6) | */ | |
672 | O_bit_or_not, /* (7) ! */ | |
673 | O_bit_exclusive_or, /* (8) ^ */ | |
674 | O_bit_and, /* (9) & */ | |
675 | O_add, /* (10) + */ | |
676 | O_subtract /* (11) - */ | |
677 | } | |
678 | operatorT; | |
679 | ||
680 | #define __ O_illegal | |
681 | ||
682 | static const operatorT op_encoding [256] = { /* maps ASCII -> operators */ | |
683 | ||
684 | __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, | |
685 | __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, | |
686 | ||
687 | __, O_bit_or_not, __, __, __, O_modulus, O_bit_and, __, | |
688 | __, __, O_multiply, O_add, __, O_subtract, __, O_divide, | |
689 | __, __, __, __, __, __, __, __, | |
690 | __, __, __, __, O_left_shift, __, O_right_shift, __, | |
691 | __, __, __, __, __, __, __, __, | |
692 | __, __, __, __, __, __, __, __, | |
693 | __, __, __, __, __, __, __, __, | |
694 | __, __, __, __, __, __, O_bit_exclusive_or, __, | |
695 | __, __, __, __, __, __, __, __, | |
696 | __, __, __, __, __, __, __, __, | |
697 | __, __, __, __, __, __, __, __, | |
698 | __, __, __, __, O_bit_inclusive_or, __, __, __, | |
699 | ||
700 | __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, | |
701 | __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, | |
702 | __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, | |
703 | __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, | |
704 | __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, | |
705 | __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, | |
706 | __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, | |
707 | __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __ | |
708 | }; | |
709 | ||
710 | ||
711 | /* | |
712 | * Rank Examples | |
713 | * 0 operand, (expression) | |
714 | * 1 + - | |
715 | * 2 & ^ ! | | |
716 | * 3 * / % < > | |
717 | */ | |
718 | typedef char operator_rankT; | |
719 | static const operator_rankT | |
720 | op_rank [] = { 0, 3, 3, 3, 3, 3, 2, 2, 2, 2, 1, 1 }; | |
721 | \f | |
722 | segT /* Return resultP -> X_seg. */ | |
723 | expr (rank, resultP) | |
724 | register operator_rankT rank; /* Larger # is higher rank. */ | |
725 | register expressionS * resultP; /* Deliver result here. */ | |
726 | { | |
727 | expressionS right; | |
728 | register operatorT op_left; | |
729 | register char c_left; /* 1st operator character. */ | |
730 | register operatorT op_right; | |
731 | register char c_right; | |
732 | ||
733 | know( rank >= 0 ); | |
734 | (void)operand (resultP); | |
735 | know( * input_line_pointer != ' ' ); /* Operand() gobbles spaces. */ | |
736 | c_left = * input_line_pointer; /* Potential operator character. */ | |
737 | op_left = op_encoding [c_left]; | |
738 | while (op_left != O_illegal && op_rank [(int) op_left] > rank) | |
739 | { | |
740 | input_line_pointer ++; /* -> after 1st character of operator. */ | |
741 | /* Operators "<<" and ">>" have 2 characters. */ | |
742 | if (* input_line_pointer == c_left && (c_left == '<' || c_left == '>') ) | |
743 | { | |
744 | input_line_pointer ++; | |
745 | } /* -> after operator. */ | |
746 | if (SEG_NONE == expr (op_rank[(int) op_left], &right)) | |
747 | { | |
748 | as_warn("Missing operand value assumed absolute 0."); | |
749 | resultP -> X_add_number = 0; | |
750 | resultP -> X_subtract_symbol = NULL; | |
751 | resultP -> X_add_symbol = NULL; | |
752 | resultP -> X_seg = SEG_ABSOLUTE; | |
753 | } | |
754 | know( * input_line_pointer != ' ' ); | |
755 | c_right = * input_line_pointer; | |
756 | op_right = op_encoding [c_right]; | |
757 | if (* input_line_pointer == c_right && (c_right == '<' || c_right == '>') ) | |
758 | { | |
759 | input_line_pointer ++; | |
760 | } /* -> after operator. */ | |
761 | know( (int) op_right == 0 | |
762 | || op_rank [(int) op_right] <= op_rank[(int) op_left] ); | |
763 | /* input_line_pointer -> after right-hand quantity. */ | |
764 | /* left-hand quantity in resultP */ | |
765 | /* right-hand quantity in right. */ | |
766 | /* operator in op_left. */ | |
767 | if ( resultP -> X_seg == SEG_PASS1 || right . X_seg == SEG_PASS1 ) | |
768 | { | |
769 | resultP -> X_seg = SEG_PASS1; | |
770 | } | |
771 | else | |
772 | { | |
773 | if ( resultP -> X_seg == SEG_BIG ) | |
774 | { | |
775 | as_warn( "Left operand of %c is a %s. Integer 0 assumed.", | |
776 | c_left, resultP -> X_add_number > 0 ? "bignum" : "float"); | |
777 | resultP -> X_seg = SEG_ABSOLUTE; | |
778 | resultP -> X_add_symbol = 0; | |
779 | resultP -> X_subtract_symbol = 0; | |
780 | resultP -> X_add_number = 0; | |
781 | } | |
782 | if ( right . X_seg == SEG_BIG ) | |
783 | { | |
784 | as_warn( "Right operand of %c is a %s. Integer 0 assumed.", | |
785 | c_left, right . X_add_number > 0 ? "bignum" : "float"); | |
786 | right . X_seg = SEG_ABSOLUTE; | |
787 | right . X_add_symbol = 0; | |
788 | right . X_subtract_symbol = 0; | |
789 | right . X_add_number = 0; | |
790 | } | |
791 | if ( op_left == O_subtract ) | |
792 | { | |
793 | /* | |
794 | * Convert - into + by exchanging symbols and negating number. | |
795 | * I know -infinity can't be negated in 2's complement: | |
796 | * but then it can't be subtracted either. This trick | |
797 | * does not cause any further inaccuracy. | |
798 | */ | |
799 | ||
800 | register struct symbol * symbolP; | |
801 | ||
802 | right . X_add_number = - right . X_add_number; | |
803 | symbolP = right . X_add_symbol; | |
804 | right . X_add_symbol = right . X_subtract_symbol; | |
805 | right . X_subtract_symbol = symbolP; | |
806 | if (symbolP) | |
807 | { | |
808 | right . X_seg = SEG_DIFFERENCE; | |
809 | } | |
810 | op_left = O_add; | |
811 | } | |
812 | \f | |
813 | if ( op_left == O_add ) | |
814 | { | |
815 | segT seg1; | |
816 | segT seg2; | |
817 | ||
818 | know( resultP -> X_seg == SEG_DATA | |
819 | || resultP -> X_seg == SEG_TEXT | |
820 | || resultP -> X_seg == SEG_BSS | |
821 | || resultP -> X_seg == SEG_UNKNOWN | |
822 | || resultP -> X_seg == SEG_DIFFERENCE | |
823 | || resultP -> X_seg == SEG_ABSOLUTE | |
824 | || resultP -> X_seg == SEG_PASS1 | |
825 | ); | |
826 | know( right . X_seg == SEG_DATA | |
827 | || right . X_seg == SEG_TEXT | |
828 | || right . X_seg == SEG_BSS | |
829 | || right . X_seg == SEG_UNKNOWN | |
830 | || right . X_seg == SEG_DIFFERENCE | |
831 | || right . X_seg == SEG_ABSOLUTE | |
832 | || right . X_seg == SEG_PASS1 | |
833 | ); | |
834 | ||
835 | clean_up_expression (& right); | |
836 | clean_up_expression (resultP); | |
837 | ||
838 | seg1 = expr_part (& resultP -> X_add_symbol, right . X_add_symbol); | |
839 | seg2 = expr_part (& resultP -> X_subtract_symbol, right . X_subtract_symbol); | |
840 | if (seg1 == SEG_PASS1 || seg2 == SEG_PASS1) { | |
841 | need_pass_2 = TRUE; | |
842 | resultP -> X_seg = SEG_PASS1; | |
843 | } else if (seg2 == SEG_ABSOLUTE) | |
844 | resultP -> X_seg = seg1; | |
845 | else if ( seg1 != SEG_UNKNOWN | |
846 | && seg1 != SEG_ABSOLUTE | |
847 | && seg2 != SEG_UNKNOWN | |
848 | && seg1 != seg2) { | |
849 | know( seg2 != SEG_ABSOLUTE ); | |
850 | know( resultP -> X_subtract_symbol ); | |
851 | ||
852 | know( seg1 == SEG_TEXT || seg1 == SEG_DATA || seg1== SEG_BSS ); | |
853 | know( seg2 == SEG_TEXT || seg2 == SEG_DATA || seg2== SEG_BSS ); | |
854 | know( resultP -> X_add_symbol ); | |
855 | know( resultP -> X_subtract_symbol ); | |
856 | as_warn("Expression too complex: forgetting %s - %s", | |
857 | resultP -> X_add_symbol -> sy_name, | |
858 | resultP -> X_subtract_symbol -> sy_name); | |
859 | resultP -> X_seg = SEG_ABSOLUTE; | |
860 | /* Clean_up_expression() will do the rest. */ | |
861 | } else | |
862 | resultP -> X_seg = SEG_DIFFERENCE; | |
863 | ||
864 | resultP -> X_add_number += right . X_add_number; | |
865 | clean_up_expression (resultP); | |
866 | } | |
867 | else | |
868 | { /* Not +. */ | |
869 | if ( resultP -> X_seg == SEG_UNKNOWN || right . X_seg == SEG_UNKNOWN ) | |
870 | { | |
871 | resultP -> X_seg = SEG_PASS1; | |
872 | need_pass_2 = TRUE; | |
873 | } | |
874 | else | |
875 | { | |
876 | resultP -> X_subtract_symbol = NULL; | |
877 | resultP -> X_add_symbol = NULL; | |
878 | /* Will be SEG_ABSOLUTE. */ | |
879 | if ( resultP -> X_seg != SEG_ABSOLUTE || right . X_seg != SEG_ABSOLUTE ) | |
880 | { | |
881 | as_warn( "Relocation error. Absolute 0 assumed."); | |
882 | resultP -> X_seg = SEG_ABSOLUTE; | |
883 | resultP -> X_add_number = 0; | |
884 | } | |
885 | else | |
886 | { | |
887 | switch ( op_left ) | |
888 | { | |
889 | case O_bit_inclusive_or: | |
890 | resultP -> X_add_number |= right . X_add_number; | |
891 | break; | |
892 | ||
893 | case O_modulus: | |
894 | if (right . X_add_number) | |
895 | { | |
896 | resultP -> X_add_number %= right . X_add_number; | |
897 | } | |
898 | else | |
899 | { | |
900 | as_warn( "Division by 0. 0 assumed." ); | |
901 | resultP -> X_add_number = 0; | |
902 | } | |
903 | break; | |
904 | ||
905 | case O_bit_and: | |
906 | resultP -> X_add_number &= right . X_add_number; | |
907 | break; | |
908 | ||
909 | case O_multiply: | |
910 | resultP -> X_add_number *= right . X_add_number; | |
911 | break; | |
912 | ||
913 | case O_divide: | |
914 | if (right . X_add_number) | |
915 | { | |
916 | resultP -> X_add_number /= right . X_add_number; | |
917 | } | |
918 | else | |
919 | { | |
920 | as_warn( "Division by 0. 0 assumed." ); | |
921 | resultP -> X_add_number = 0; | |
922 | } | |
923 | break; | |
924 | ||
925 | case O_left_shift: | |
926 | resultP -> X_add_number <<= right . X_add_number; | |
927 | break; | |
928 | ||
929 | case O_right_shift: | |
930 | resultP -> X_add_number >>= right . X_add_number; | |
931 | break; | |
932 | ||
933 | case O_bit_exclusive_or: | |
934 | resultP -> X_add_number ^= right . X_add_number; | |
935 | break; | |
936 | ||
937 | case O_bit_or_not: | |
938 | resultP -> X_add_number |= ~ right . X_add_number; | |
939 | break; | |
940 | ||
941 | default: | |
942 | BAD_CASE( op_left ); | |
943 | break; | |
944 | } /* switch(operator) */ | |
945 | } | |
946 | } /* If we have to force need_pass_2. */ | |
947 | } /* If operator was +. */ | |
948 | } /* If we didn't set need_pass_2. */ | |
949 | op_left = op_right; | |
950 | } /* While next operator is >= this rank. */ | |
951 | return (resultP -> X_seg); | |
952 | } | |
953 | \f | |
954 | /* | |
955 | * get_symbol_end() | |
956 | * | |
957 | * This lives here because it belongs equally in expr.c & read.c. | |
958 | * Expr.c is just a branch office read.c anyway, and putting it | |
959 | * here lessens the crowd at read.c. | |
960 | * | |
961 | * Assume input_line_pointer is at start of symbol name. | |
962 | * Advance input_line_pointer past symbol name. | |
963 | * Turn that character into a '\0', returning its former value. | |
964 | * This allows a string compare (RMS wants symbol names to be strings) | |
965 | * of the symbol name. | |
966 | * There will always be a char following symbol name, because all good | |
967 | * lines end in end-of-line. | |
968 | */ | |
969 | char | |
970 | get_symbol_end() | |
971 | { | |
972 | register char c; | |
973 | ||
974 | while ( is_part_of_name( c = * input_line_pointer ++ ) ) | |
975 | ; | |
976 | * -- input_line_pointer = 0; | |
977 | return (c); | |
978 | } | |
979 | ||
980 | /* end: expr.c */ |