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