Back to index

cell-binutils  2.17cvs20070401
Classes | Defines | Functions | Variables
expr.c File Reference
#include "as.h"
#include "safe-ctype.h"
#include "obstack.h"

Go to the source code of this file.

Classes

struct  expr_symbol_line

Defines

#define min(a, b)   ((a) < (b) ? (a) : (b))
#define valuesize   32
#define __   O_illegal
#define O_SINGLE_EQ   O_illegal
#define STANDARD_MUL_PRECEDENCE   8
#define MRI_MUL_PRECEDENCE   6

Functions

static void floating_constant (expressionS *expressionP)
static valueT generic_bignum_to_int32 (void)
static void integer_constant (int radix, expressionS *expressionP)
static void mri_char_constant (expressionS *)
static void current_location (expressionS *)
static void clean_up_expression (expressionS *expressionP)
static segT operand (expressionS *, enum expr_mode)
static operatorT operator (int *)
symbolS * make_expr_symbol (expressionS *expressionP)
int expr_symbol_where (symbolS *sym, char **pfile, unsigned int *pline)
symbolS * expr_build_uconstant (offsetT value)
symbolS * expr_build_dot (void)
void expr_set_precedence (void)
void expr_begin (void)
segT expr (int rankarg, expressionS *resultP, enum expr_mode mode)
int resolve_expression (expressionS *expressionP)
char get_symbol_end (void)
unsigned int get_single_number (void)

Variables

const char EXP_CHARS []
const char FLT_CHARS []
static struct expr_symbol_lineexpr_symbol_lines
LITTLENUM_TYPE generic_bignum [SIZE_OF_LARGE_NUMBER+6]
FLONUM_TYPE generic_floating_point_number
static const operatorT op_encoding [256]
static operator_rankT op_rank []

Class Documentation

struct expr_symbol_line

Definition at line 51 of file expr.c.

Collaboration diagram for expr_symbol_line:
Class Members
char * file
unsigned int line
struct expr_symbol_line * next
symbolS * sym

Define Documentation

#define __   O_illegal

Definition at line 1385 of file expr.c.

#define min (   a,
  b 
)    ((a) < (b) ? (a) : (b))

Definition at line 28 of file expr.c.

#define MRI_MUL_PRECEDENCE   6

Definition at line 1491 of file expr.c.

#define O_SINGLE_EQ   O_illegal

Definition at line 1387 of file expr.c.

#define STANDARD_MUL_PRECEDENCE   8

Definition at line 1490 of file expr.c.

#define valuesize   32

Function Documentation

static void clean_up_expression ( expressionS expressionP) [static]

Definition at line 1340 of file expr.c.

{
  switch (expressionP->X_op)
    {
    case O_illegal:
    case O_absent:
      expressionP->X_add_number = 0;
      /* Fall through.  */
    case O_big:
    case O_constant:
    case O_register:
      expressionP->X_add_symbol = NULL;
      /* Fall through.  */
    case O_symbol:
    case O_uminus:
    case O_bit_not:
      expressionP->X_op_symbol = NULL;
      break;
    default:
      break;
    }
}

Here is the caller graph for this function:

static void current_location ( expressionS expressionp) [static]

Definition at line 690 of file expr.c.

{
  if (now_seg == absolute_section)
    {
      expressionp->X_op = O_constant;
      expressionp->X_add_number = abs_section_offset;
    }
  else
    {
      expressionp->X_op = O_symbol;
      expressionp->X_add_symbol = symbol_temp_new_now ();
      expressionp->X_add_number = 0;
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

segT expr ( int  rankarg,
expressionS resultP,
enum expr_mode  mode 
)

Definition at line 1628 of file expr.c.

{
  operator_rankT rank = (operator_rankT) rankarg;
  segT retval;
  expressionS right;
  operatorT op_left;
  operatorT op_right;
  int op_chars;

  know (rank >= 0);

  /* Save the value of dot for the fixup code.  */
  if (rank == 0)
    dot_value = frag_now_fix ();

  retval = operand (resultP, mode);

  /* operand () gobbles spaces.  */
  know (*input_line_pointer != ' ');

  op_left = operator (&op_chars);
  while (op_left != O_illegal && op_rank[(int) op_left] > rank)
    {
      segT rightseg;
      bfd_vma frag_off;

      input_line_pointer += op_chars;     /* -> after operator.  */

      rightseg = expr (op_rank[(int) op_left], &right, mode);
      if (right.X_op == O_absent)
       {
         as_warn (_("missing operand; zero assumed"));
         right.X_op = O_constant;
         right.X_add_number = 0;
         right.X_add_symbol = NULL;
         right.X_op_symbol = NULL;
       }

      know (*input_line_pointer != ' ');

      if (op_left == O_index)
       {
         if (*input_line_pointer != ']')
           as_bad ("missing right bracket");
         else
           {
             ++input_line_pointer;
             SKIP_WHITESPACE ();
           }
       }

      op_right = operator (&op_chars);

      know (op_right == O_illegal
           || op_rank[(int) op_right] <= op_rank[(int) op_left]);
      know ((int) op_left >= (int) O_multiply
           && (int) op_left <= (int) O_index);

      /* input_line_pointer->after right-hand quantity.  */
      /* left-hand quantity in resultP.  */
      /* right-hand quantity in right.  */
      /* operator in op_left.  */

      if (resultP->X_op == O_big)
       {
         if (resultP->X_add_number > 0)
           as_warn (_("left operand is a bignum; integer 0 assumed"));
         else
           as_warn (_("left operand is a float; integer 0 assumed"));
         resultP->X_op = O_constant;
         resultP->X_add_number = 0;
         resultP->X_add_symbol = NULL;
         resultP->X_op_symbol = NULL;
       }
      if (right.X_op == O_big)
       {
         if (right.X_add_number > 0)
           as_warn (_("right operand is a bignum; integer 0 assumed"));
         else
           as_warn (_("right operand is a float; integer 0 assumed"));
         right.X_op = O_constant;
         right.X_add_number = 0;
         right.X_add_symbol = NULL;
         right.X_op_symbol = NULL;
       }

      /* Optimize common cases.  */
#ifdef md_optimize_expr
      if (md_optimize_expr (resultP, op_left, &right))
       {
         /* Skip.  */
         ;
       }
      else
#endif
      if (op_left == O_add && right.X_op == O_constant)
       {
         /* X + constant.  */
         resultP->X_add_number += right.X_add_number;
       }
      /* This case comes up in PIC code.  */
      else if (op_left == O_subtract
              && right.X_op == O_symbol
              && resultP->X_op == O_symbol
              && retval == rightseg
              && (SEG_NORMAL (rightseg)
                 || right.X_add_symbol == resultP->X_add_symbol)
              && frag_offset_fixed_p (symbol_get_frag (resultP->X_add_symbol),
                                   symbol_get_frag (right.X_add_symbol),
                                   &frag_off))
       {
         resultP->X_add_number -= right.X_add_number;
         resultP->X_add_number -= frag_off / OCTETS_PER_BYTE;
         resultP->X_add_number += (S_GET_VALUE (resultP->X_add_symbol)
                                - S_GET_VALUE (right.X_add_symbol));
         resultP->X_op = O_constant;
         resultP->X_add_symbol = 0;
       }
      else if (op_left == O_subtract && right.X_op == O_constant)
       {
         /* X - constant.  */
         resultP->X_add_number -= right.X_add_number;
       }
      else if (op_left == O_add && resultP->X_op == O_constant)
       {
         /* Constant + X.  */
         resultP->X_op = right.X_op;
         resultP->X_add_symbol = right.X_add_symbol;
         resultP->X_op_symbol = right.X_op_symbol;
         resultP->X_add_number += right.X_add_number;
         retval = rightseg;
       }
      else if (resultP->X_op == O_constant && right.X_op == O_constant)
       {
         /* Constant OP constant.  */
         offsetT v = right.X_add_number;
         if (v == 0 && (op_left == O_divide || op_left == O_modulus))
           {
             as_warn (_("division by zero"));
             v = 1;
           }
         switch (op_left)
           {
           default:                abort ();
           case O_multiply:        resultP->X_add_number *= v; break;
           case O_divide:          resultP->X_add_number /= v; break;
           case O_modulus:         resultP->X_add_number %= v; break;
           case O_left_shift:             resultP->X_add_number <<= v; break;
           case O_right_shift:
             /* We always use unsigned shifts, to avoid relying on
               characteristics of the compiler used to compile gas.  */
             resultP->X_add_number =
              (offsetT) ((valueT) resultP->X_add_number >> (valueT) v);
             break;
           case O_bit_inclusive_or:       resultP->X_add_number |= v; break;
           case O_bit_or_not:             resultP->X_add_number |= ~v; break;
           case O_bit_exclusive_or:       resultP->X_add_number ^= v; break;
           case O_bit_and:         resultP->X_add_number &= v; break;
             /* Constant + constant (O_add) is handled by the
               previous if statement for constant + X, so is omitted
               here.  */
           case O_subtract:        resultP->X_add_number -= v; break;
           case O_eq:
             resultP->X_add_number =
              resultP->X_add_number == v ? ~ (offsetT) 0 : 0;
             break;
           case O_ne:
             resultP->X_add_number =
              resultP->X_add_number != v ? ~ (offsetT) 0 : 0;
             break;
           case O_lt:
             resultP->X_add_number =
              resultP->X_add_number <  v ? ~ (offsetT) 0 : 0;
             break;
           case O_le:
             resultP->X_add_number =
              resultP->X_add_number <= v ? ~ (offsetT) 0 : 0;
             break;
           case O_ge:
             resultP->X_add_number =
              resultP->X_add_number >= v ? ~ (offsetT) 0 : 0;
             break;
           case O_gt:
             resultP->X_add_number =
              resultP->X_add_number >  v ? ~ (offsetT) 0 : 0;
             break;
           case O_logical_and:
             resultP->X_add_number = resultP->X_add_number && v;
             break;
           case O_logical_or:
             resultP->X_add_number = resultP->X_add_number || v;
             break;
           }
       }
      else if (resultP->X_op == O_symbol
              && right.X_op == O_symbol
              && (op_left == O_add
                 || op_left == O_subtract
                 || (resultP->X_add_number == 0
                     && right.X_add_number == 0)))
       {
         /* Symbol OP symbol.  */
         resultP->X_op = op_left;
         resultP->X_op_symbol = right.X_add_symbol;
         if (op_left == O_add)
           resultP->X_add_number += right.X_add_number;
         else if (op_left == O_subtract)
           {
             resultP->X_add_number -= right.X_add_number;
             if (retval == rightseg && SEG_NORMAL (retval))
              {
                retval = absolute_section;
                rightseg = absolute_section;
              }
           }
       }
      else
       {
         /* The general case.  */
         resultP->X_add_symbol = make_expr_symbol (resultP);
         resultP->X_op_symbol = make_expr_symbol (&right);
         resultP->X_op = op_left;
         resultP->X_add_number = 0;
         resultP->X_unsigned = 1;
       }

      if (retval != rightseg)
       {
         if (! SEG_NORMAL (retval))
           {
             if (retval != undefined_section || SEG_NORMAL (rightseg))
              retval = rightseg;
           }
         else if (SEG_NORMAL (rightseg)
#ifdef DIFF_EXPR_OK
                 && op_left != O_subtract
#endif
                 )
           as_bad (_("operation combines symbols in different segments"));
       }

      op_left = op_right;
    }                       /* While next operator is >= this rank.  */

  /* The PA port needs this information.  */
  if (resultP->X_add_symbol)
    symbol_mark_used (resultP->X_add_symbol);

  if (rank == 0 && mode == expr_evaluate)
    resolve_expression (resultP);

  return resultP->X_op == O_constant ? absolute_section : retval;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void expr_begin ( void  )

Definition at line 1513 of file expr.c.

{
  expr_set_precedence ();

  /* Verify that X_op field is wide enough.  */
  {
    expressionS e;
    e.X_op = O_max;
    assert (e.X_op == O_max);
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

symbolS* expr_build_dot ( void  )

Definition at line 162 of file expr.c.

Here is the call graph for this function:

Here is the caller graph for this function:

symbolS* expr_build_uconstant ( offsetT  value)

Definition at line 149 of file expr.c.

Here is the call graph for this function:

Here is the caller graph for this function:

void expr_set_precedence ( void  )
int expr_symbol_where ( symbolS *  sym,
char **  pfile,
unsigned int pline 
)

Definition at line 119 of file expr.c.

{
  register struct expr_symbol_line *l;

  for (l = expr_symbol_lines; l != NULL; l = l->next)
    {
      if (l->sym == sym)
       {
         *pfile = l->file;
         *pline = l->line;
         return 1;
       }
    }

  return 0;
}

Here is the caller graph for this function:

static void floating_constant ( expressionS expressionP) [static]

Definition at line 190 of file expr.c.

{
  /* input_line_pointer -> floating-point constant.  */
  int error_code;

  error_code = atof_generic (&input_line_pointer, ".", EXP_CHARS,
                          &generic_floating_point_number);

  if (error_code)
    {
      if (error_code == ERROR_EXPONENT_OVERFLOW)
       {
         as_bad (_("bad floating-point constant: exponent overflow"));
       }
      else
       {
         as_bad (_("bad floating-point constant: unknown error code=%d"),
                error_code);
       }
    }
  expressionP->X_op = O_big;
  /* input_line_pointer -> just after constant, which may point to
     whitespace.  */
  expressionP->X_add_number = -1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static valueT generic_bignum_to_int32 ( void  ) [static]

Definition at line 217 of file expr.c.

{
  valueT number =
          ((generic_bignum[1] & LITTLENUM_MASK) << LITTLENUM_NUMBER_OF_BITS)
          | (generic_bignum[0] & LITTLENUM_MASK);
  number &= 0xffffffff;
  return number;
}

Here is the caller graph for this function:

Definition at line 2174 of file expr.c.

{
  expressionS exp;
  operand (&exp, expr_normal);
  return exp.X_add_number;
}

Here is the caller graph for this function:

char get_symbol_end ( void  )

Definition at line 2155 of file expr.c.

{
  char c;

  /* We accept \001 in a name in case this is being called with a
     constructed string.  */
  if (is_name_beginner (c = *input_line_pointer++) || c == '\001')
    {
      while (is_part_of_name (c = *input_line_pointer++)
            || c == '\001')
       ;
      if (is_name_ender (c))
       c = *input_line_pointer++;
    }
  *--input_line_pointer = 0;
  return (c);
}
static void integer_constant ( int  radix,
expressionS expressionP 
) [static]

Definition at line 243 of file expr.c.

{
  char *start;              /* Start of number.  */
  char *suffix = NULL;
  char c;
  valueT number;     /* Offset or (absolute) value.  */
  short int digit;   /* Value of next digit in current radix.  */
  short int maxdig = 0;     /* Highest permitted digit value.  */
  int too_many_digits = 0;  /* If we see >= this number of.  */
  char *name;        /* Points to name of symbol.  */
  symbolS *symbolP;  /* Points to symbol.  */

  int small;                /* True if fits in 32 bits.  */

  /* May be bignum, or may fit in 32 bits.  */
  /* Most numbers fit into 32 bits, and we want this case to be fast.
     so we pretend it will fit into 32 bits.  If, after making up a 32
     bit number, we realise that we have scanned more digits than
     comfortably fit into 32 bits, we re-scan the digits coding them
     into a bignum.  For decimal and octal numbers we are
     conservative: Some numbers may be assumed bignums when in fact
     they do fit into 32 bits.  Numbers of any radix can have excess
     leading zeros: We strive to recognise this and cast them back
     into 32 bits.  We must check that the bignum really is more than
     32 bits, and change it back to a 32-bit number if it fits.  The
     number we are looking for is expected to be positive, but if it
     fits into 32 bits as an unsigned number, we let it be a 32-bit
     number.  The cavalier approach is for speed in ordinary cases.  */
  /* This has been extended for 64 bits.  We blindly assume that if
     you're compiling in 64-bit mode, the target is a 64-bit machine.
     This should be cleaned up.  */

#ifdef BFD64
#define valuesize 64
#else /* includes non-bfd case, mostly */
#define valuesize 32
#endif

  if ((NUMBERS_WITH_SUFFIX || flag_m68k_mri) && radix == 0)
    {
      int flt = 0;

      /* In MRI mode, the number may have a suffix indicating the
        radix.  For that matter, it might actually be a floating
        point constant.  */
      for (suffix = input_line_pointer; ISALNUM (*suffix); suffix++)
       {
         if (*suffix == 'e' || *suffix == 'E')
           flt = 1;
       }

      if (suffix == input_line_pointer)
       {
         radix = 10;
         suffix = NULL;
       }
      else
       {
         c = *--suffix;
         c = TOUPPER (c);
         /* If we have both NUMBERS_WITH_SUFFIX and LOCAL_LABELS_FB,
            we distinguish between 'B' and 'b'.  This is the case for
            Z80.  */
         if ((NUMBERS_WITH_SUFFIX && LOCAL_LABELS_FB ? *suffix : c) == 'B')
           radix = 2;
         else if (c == 'D')
           radix = 10;
         else if (c == 'O' || c == 'Q')
           radix = 8;
         else if (c == 'H')
           radix = 16;
         else if (suffix[1] == '.' || c == 'E' || flt)
           {
             floating_constant (expressionP);
             return;
           }
         else
           {
             radix = 10;
             suffix = NULL;
           }
       }
    }

  switch (radix)
    {
    case 2:
      maxdig = 2;
      too_many_digits = valuesize + 1;
      break;
    case 8:
      maxdig = radix = 8;
      too_many_digits = (valuesize + 2) / 3 + 1;
      break;
    case 16:
      maxdig = radix = 16;
      too_many_digits = (valuesize + 3) / 4 + 1;
      break;
    case 10:
      maxdig = radix = 10;
      too_many_digits = (valuesize + 11) / 4; /* Very rough.  */
    }
#undef valuesize
  start = input_line_pointer;
  c = *input_line_pointer++;
  for (number = 0;
       (digit = hex_value (c)) < maxdig;
       c = *input_line_pointer++)
    {
      number = number * radix + digit;
    }
  /* c contains character after number.  */
  /* input_line_pointer->char after c.  */
  small = (input_line_pointer - start - 1) < too_many_digits;

  if (radix == 16 && c == '_')
    {
      /* This is literal of the form 0x333_0_12345678_1.
        This example is equivalent to 0x00000333000000001234567800000001.  */

      int num_little_digits = 0;
      int i;
      input_line_pointer = start;  /* -> 1st digit.  */

      know (LITTLENUM_NUMBER_OF_BITS == 16);

      for (c = '_'; c == '_'; num_little_digits += 2)
       {

         /* Convert one 64-bit word.  */
         int ndigit = 0;
         number = 0;
         for (c = *input_line_pointer++;
              (digit = hex_value (c)) < maxdig;
              c = *(input_line_pointer++))
           {
             number = number * radix + digit;
             ndigit++;
           }

         /* Check for 8 digit per word max.  */
         if (ndigit > 8)
           as_bad (_("a bignum with underscores may not have more than 8 hex digits in any word"));

         /* Add this chunk to the bignum.
            Shift things down 2 little digits.  */
         know (LITTLENUM_NUMBER_OF_BITS == 16);
         for (i = min (num_little_digits + 1, SIZE_OF_LARGE_NUMBER - 1);
              i >= 2;
              i--)
           generic_bignum[i] = generic_bignum[i - 2];

         /* Add the new digits as the least significant new ones.  */
         generic_bignum[0] = number & 0xffffffff;
         generic_bignum[1] = number >> 16;
       }

      /* Again, c is char after number, input_line_pointer->after c.  */

      if (num_little_digits > SIZE_OF_LARGE_NUMBER - 1)
       num_little_digits = SIZE_OF_LARGE_NUMBER - 1;

      assert (num_little_digits >= 4);

      if (num_little_digits != 8)
       as_bad (_("a bignum with underscores must have exactly 4 words"));

      /* We might have some leading zeros.  These can be trimmed to give
        us a change to fit this constant into a small number.  */
      while (generic_bignum[num_little_digits - 1] == 0
            && num_little_digits > 1)
       num_little_digits--;

      if (num_little_digits <= 2)
       {
         /* will fit into 32 bits.  */
         number = generic_bignum_to_int32 ();
         small = 1;
       }
#ifdef BFD64
      else if (num_little_digits <= 4)
       {
         /* Will fit into 64 bits.  */
         number = generic_bignum_to_int64 ();
         small = 1;
       }
#endif
      else
       {
         small = 0;

         /* Number of littlenums in the bignum.  */
         number = num_little_digits;
       }
    }
  else if (!small)
    {
      /* We saw a lot of digits. manufacture a bignum the hard way.  */
      LITTLENUM_TYPE *leader;      /* -> high order littlenum of the bignum.  */
      LITTLENUM_TYPE *pointer;     /* -> littlenum we are frobbing now.  */
      long carry;

      leader = generic_bignum;
      generic_bignum[0] = 0;
      generic_bignum[1] = 0;
      generic_bignum[2] = 0;
      generic_bignum[3] = 0;
      input_line_pointer = start;  /* -> 1st digit.  */
      c = *input_line_pointer++;
      for (; (carry = hex_value (c)) < maxdig; c = *input_line_pointer++)
       {
         for (pointer = generic_bignum; pointer <= leader; pointer++)
           {
             long work;

             work = carry + radix * *pointer;
             *pointer = work & LITTLENUM_MASK;
             carry = work >> LITTLENUM_NUMBER_OF_BITS;
           }
         if (carry)
           {
             if (leader < generic_bignum + SIZE_OF_LARGE_NUMBER - 1)
              {
                /* Room to grow a longer bignum.  */
                *++leader = carry;
              }
           }
       }
      /* Again, c is char after number.  */
      /* input_line_pointer -> after c.  */
      know (LITTLENUM_NUMBER_OF_BITS == 16);
      if (leader < generic_bignum + 2)
       {
         /* Will fit into 32 bits.  */
         number = generic_bignum_to_int32 ();
         small = 1;
       }
#ifdef BFD64
      else if (leader < generic_bignum + 4)
       {
         /* Will fit into 64 bits.  */
         number = generic_bignum_to_int64 ();
         small = 1;
       }
#endif
      else
       {
         /* Number of littlenums in the bignum.  */
         number = leader - generic_bignum + 1;
       }
    }

  if ((NUMBERS_WITH_SUFFIX || flag_m68k_mri)
      && suffix != NULL
      && input_line_pointer - 1 == suffix)
    c = *input_line_pointer++;

  if (small)
    {
      /* Here with number, in correct radix. c is the next char.
        Note that unlike un*x, we allow "011f" "0x9f" to both mean
        the same as the (conventional) "9f".
        This is simply easier than checking for strict canonical
        form.  Syntax sux!  */

      if (LOCAL_LABELS_FB && c == 'b')
       {
         /* Backward ref to local label.
            Because it is backward, expect it to be defined.  */
         /* Construct a local label.  */
         name = fb_label_name ((int) number, 0);

         /* Seen before, or symbol is defined: OK.  */
         symbolP = symbol_find (name);
         if ((symbolP != NULL) && (S_IS_DEFINED (symbolP)))
           {
             /* Local labels are never absolute.  Don't waste time
               checking absoluteness.  */
             know (SEG_NORMAL (S_GET_SEGMENT (symbolP)));

             expressionP->X_op = O_symbol;
             expressionP->X_add_symbol = symbolP;
           }
         else
           {
             /* Either not seen or not defined.  */
             /* @@ Should print out the original string instead of
               the parsed number.  */
             as_bad (_("backward ref to unknown label \"%d:\""),
                    (int) number);
             expressionP->X_op = O_constant;
           }

         expressionP->X_add_number = 0;
       }                    /* case 'b' */
      else if (LOCAL_LABELS_FB && c == 'f')
       {
         /* Forward reference.  Expect symbol to be undefined or
            unknown.  undefined: seen it before.  unknown: never seen
            it before.

            Construct a local label name, then an undefined symbol.
            Don't create a xseg frag for it: caller may do that.
            Just return it as never seen before.  */
         name = fb_label_name ((int) number, 1);
         symbolP = symbol_find_or_make (name);
         /* We have no need to check symbol properties.  */
#ifndef many_segments
         /* Since "know" puts its arg into a "string", we
            can't have newlines in the argument.  */
         know (S_GET_SEGMENT (symbolP) == undefined_section || S_GET_SEGMENT (symbolP) == text_section || S_GET_SEGMENT (symbolP) == data_section);
#endif
         expressionP->X_op = O_symbol;
         expressionP->X_add_symbol = symbolP;
         expressionP->X_add_number = 0;
       }                    /* case 'f' */
      else if (LOCAL_LABELS_DOLLAR && c == '$')
       {
         /* If the dollar label is *currently* defined, then this is just
            another reference to it.  If it is not *currently* defined,
            then this is a fresh instantiation of that number, so create
            it.  */

         if (dollar_label_defined ((long) number))
           {
             name = dollar_label_name ((long) number, 0);
             symbolP = symbol_find (name);
             know (symbolP != NULL);
           }
         else
           {
             name = dollar_label_name ((long) number, 1);
             symbolP = symbol_find_or_make (name);
           }

         expressionP->X_op = O_symbol;
         expressionP->X_add_symbol = symbolP;
         expressionP->X_add_number = 0;
       }                    /* case '$' */
      else
       {
         expressionP->X_op = O_constant;
         expressionP->X_add_number = number;
         input_line_pointer--;     /* Restore following character.  */
       }                    /* Really just a number.  */
    }
  else
    {
      /* Not a small number.  */
      expressionP->X_op = O_big;
      expressionP->X_add_number = number; /* Number of littlenums.  */
      input_line_pointer--; /* -> char following number.  */
    }
}

Here is the call graph for this function:

symbolS* make_expr_symbol ( expressionS expressionP)

Definition at line 65 of file expr.c.

{
  expressionS zero;
  symbolS *symbolP;
  struct expr_symbol_line *n;

  if (expressionP->X_op == O_symbol
      && expressionP->X_add_number == 0)
    return expressionP->X_add_symbol;

  if (expressionP->X_op == O_big)
    {
      /* This won't work, because the actual value is stored in
        generic_floating_point_number or generic_bignum, and we are
        going to lose it if we haven't already.  */
      if (expressionP->X_add_number > 0)
       as_bad (_("bignum invalid"));
      else
       as_bad (_("floating point number invalid"));
      zero.X_op = O_constant;
      zero.X_add_number = 0;
      zero.X_unsigned = 0;
      clean_up_expression (&zero);
      expressionP = &zero;
    }

  /* Putting constant symbols in absolute_section rather than
     expr_section is convenient for the old a.out code, for which
     S_GET_SEGMENT does not always retrieve the value put in by
     S_SET_SEGMENT.  */
  symbolP = symbol_create (FAKE_LABEL_NAME,
                        (expressionP->X_op == O_constant
                         ? absolute_section
                         : expr_section),
                        0, &zero_address_frag);
  symbol_set_value_expression (symbolP, expressionP);

  if (expressionP->X_op == O_constant)
    resolve_symbol_value (symbolP);

  n = (struct expr_symbol_line *) xmalloc (sizeof *n);
  n->sym = symbolP;
  as_where (&n->file, &n->line);
  n->next = expr_symbol_lines;
  expr_symbol_lines = n;

  return symbolP;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void mri_char_constant ( expressionS expressionP) [static]

Definition at line 601 of file expr.c.

{
  int i;

  if (*input_line_pointer == '\''
      && input_line_pointer[1] != '\'')
    {
      expressionP->X_op = O_constant;
      expressionP->X_add_number = 0;
      return;
    }

  /* In order to get the correct byte ordering, we must build the
     number in reverse.  */
  for (i = SIZE_OF_LARGE_NUMBER - 1; i >= 0; i--)
    {
      int j;

      generic_bignum[i] = 0;
      for (j = 0; j < CHARS_PER_LITTLENUM; j++)
       {
         if (*input_line_pointer == '\'')
           {
             if (input_line_pointer[1] != '\'')
              break;
             ++input_line_pointer;
           }
         generic_bignum[i] <<= 8;
         generic_bignum[i] += *input_line_pointer;
         ++input_line_pointer;
       }

      if (i < SIZE_OF_LARGE_NUMBER - 1)
       {
         /* If there is more than one littlenum, left justify the
            last one to make it match the earlier ones.  If there is
            only one, we can just use the value directly.  */
         for (; j < CHARS_PER_LITTLENUM; j++)
           generic_bignum[i] <<= 8;
       }

      if (*input_line_pointer == '\''
         && input_line_pointer[1] != '\'')
       break;
    }

  if (i < 0)
    {
      as_bad (_("character constant too large"));
      i = 0;
    }

  if (i > 0)
    {
      int c;
      int j;

      c = SIZE_OF_LARGE_NUMBER - i;
      for (j = 0; j < c; j++)
       generic_bignum[j] = generic_bignum[i + j];
      i = c;
    }

  know (LITTLENUM_NUMBER_OF_BITS == 16);
  if (i > 2)
    {
      expressionP->X_op = O_big;
      expressionP->X_add_number = i;
    }
  else
    {
      expressionP->X_op = O_constant;
      if (i < 2)
       expressionP->X_add_number = generic_bignum[0] & LITTLENUM_MASK;
      else
       expressionP->X_add_number =
         (((generic_bignum[1] & LITTLENUM_MASK)
           << LITTLENUM_NUMBER_OF_BITS)
          | (generic_bignum[0] & LITTLENUM_MASK));
    }

  /* Skip the final closing quote.  */
  ++input_line_pointer;
}

Here is the call graph for this function:

static segT operand ( expressionS expressionP,
enum expr_mode  mode 
) [static]
static operatorT operator ( int num_chars) [inline, static]

Definition at line 1530 of file expr.c.

{
  int c;
  operatorT ret;

  c = *input_line_pointer & 0xff;
  *num_chars = 1;

  if (is_end_of_line[c])
    return O_illegal;

  switch (c)
    {
    default:
      return op_encoding[c];

    case '+':
    case '-':
      return op_encoding[c];

    case '<':
      switch (input_line_pointer[1])
       {
       default:
         return op_encoding[c];
       case '<':
         ret = O_left_shift;
         break;
       case '>':
         ret = O_ne;
         break;
       case '=':
         ret = O_le;
         break;
       }
      *num_chars = 2;
      return ret;

    case '=':
      if (input_line_pointer[1] != '=')
       return op_encoding[c];

      *num_chars = 2;
      return O_eq;

    case '>':
      switch (input_line_pointer[1])
       {
       default:
         return op_encoding[c];
       case '>':
         ret = O_right_shift;
         break;
       case '=':
         ret = O_ge;
         break;
       }
      *num_chars = 2;
      return ret;

    case '!':
      switch (input_line_pointer[1])
       {
       case '!':
         /* We accept !! as equivalent to ^ for MRI compatibility. */
         *num_chars = 2;
         return O_bit_exclusive_or;
       case '=':
         /* We accept != as equivalent to <>.  */
         *num_chars = 2;
         return O_ne;
       default:
         if (flag_m68k_mri)
           return O_bit_inclusive_or;
         return op_encoding[c];
       }

    case '|':
      if (input_line_pointer[1] != '|')
       return op_encoding[c];

      *num_chars = 2;
      return O_logical_or;

    case '&':
      if (input_line_pointer[1] != '&')
       return op_encoding[c];

      *num_chars = 2;
      return O_logical_and;
    }

  /* NOTREACHED  */
}

Here is the caller graph for this function:

int resolve_expression ( expressionS expressionP)

Definition at line 1888 of file expr.c.

{
  /* Help out with CSE.  */
  valueT final_val = expressionP->X_add_number;
  symbolS *add_symbol = expressionP->X_add_symbol;
  symbolS *op_symbol = expressionP->X_op_symbol;
  operatorT op = expressionP->X_op;
  valueT left, right;
  segT seg_left, seg_right;
  fragS *frag_left, *frag_right;
  bfd_vma frag_off;

  switch (op)
    {
    default:
      return 0;

    case O_constant:
    case O_register:
      left = 0;
      break;

    case O_symbol:
    case O_symbol_rva:
      if (!snapshot_symbol (&add_symbol, &left, &seg_left, &frag_left))
       return 0;

      break;

    case O_uminus:
    case O_bit_not:
    case O_logical_not:
      if (!snapshot_symbol (&add_symbol, &left, &seg_left, &frag_left))
       return 0;

      if (seg_left != absolute_section)
       return 0;

      if (op == O_logical_not)
       left = !left;
      else if (op == O_uminus)
       left = -left;
      else
       left = ~left;
      op = O_constant;
      break;

    case O_multiply:
    case O_divide:
    case O_modulus:
    case O_left_shift:
    case O_right_shift:
    case O_bit_inclusive_or:
    case O_bit_or_not:
    case O_bit_exclusive_or:
    case O_bit_and:
    case O_add:
    case O_subtract:
    case O_eq:
    case O_ne:
    case O_lt:
    case O_le:
    case O_ge:
    case O_gt:
    case O_logical_and:
    case O_logical_or:
      if (!snapshot_symbol (&add_symbol, &left, &seg_left, &frag_left)
         || !snapshot_symbol (&op_symbol, &right, &seg_right, &frag_right))
       return 0;

      /* Simplify addition or subtraction of a constant by folding the
        constant into X_add_number.  */
      if (op == O_add)
       {
         if (seg_right == absolute_section)
           {
             final_val += right;
             op = O_symbol;
             break;
           }
         else if (seg_left == absolute_section)
           {
             final_val += left;
             left = right;
             seg_left = seg_right;
             add_symbol = op_symbol;
             op = O_symbol;
             break;
           }
       }
      else if (op == O_subtract)
       {
         if (seg_right == absolute_section)
           {
             final_val -= right;
             op = O_symbol;
             break;
           }
       }

      /* Equality and non-equality tests are permitted on anything.
        Subtraction, and other comparison operators are permitted if
        both operands are in the same section.
        Shifts by constant zero are permitted on anything.
        Multiplies, bit-ors, and bit-ands with constant zero are
        permitted on anything.
        Multiplies and divides by constant one are permitted on
        anything.
        Binary operations with both operands being the same register
        or undefined symbol are permitted if the result doesn't depend
        on the input value.
        Otherwise, both operands must be absolute.  We already handled
        the case of addition or subtraction of a constant above.  */
      frag_off = 0;
      if (!(seg_left == absolute_section
              && seg_right == absolute_section)
         && !(op == O_eq || op == O_ne)
         && !((op == O_subtract
              || op == O_lt || op == O_le || op == O_ge || op == O_gt)
              && seg_left == seg_right
              && (finalize_syms
                 || frag_offset_fixed_p (frag_left, frag_right, &frag_off))
              && (seg_left != reg_section || left == right)
              && (seg_left != undefined_section || add_symbol == op_symbol)))
       {
         if ((seg_left == absolute_section && left == 0)
             || (seg_right == absolute_section && right == 0))
           {
             if (op == O_bit_exclusive_or || op == O_bit_inclusive_or)
              {
                if (seg_right != absolute_section || right != 0)
                  {
                    seg_left = seg_right;
                    left = right;
                    add_symbol = op_symbol;
                  }
                op = O_symbol;
                break;
              }
             else if (op == O_left_shift || op == O_right_shift)
              {
                if (seg_left != absolute_section || left != 0)
                  {
                    op = O_symbol;
                    break;
                  }
              }
             else if (op != O_multiply
                     && op != O_bit_or_not && op != O_bit_and)
               return 0;
           }
         else if (op == O_multiply
                 && seg_left == absolute_section && left == 1)
           {
             seg_left = seg_right;
             left = right;
             add_symbol = op_symbol;
             op = O_symbol;
             break;
           }
         else if ((op == O_multiply || op == O_divide)
                 && seg_right == absolute_section && right == 1)
           {
             op = O_symbol;
             break;
           }
         else if (left != right
                 || ((seg_left != reg_section || seg_right != reg_section)
                     && (seg_left != undefined_section
                        || seg_right != undefined_section
                        || add_symbol != op_symbol)))
           return 0;
         else if (op == O_bit_and || op == O_bit_inclusive_or)
           {
             op = O_symbol;
             break;
           }
         else if (op != O_bit_exclusive_or && op != O_bit_or_not)
           return 0;
       }

      right += frag_off / OCTETS_PER_BYTE;
      switch (op)
       {
       case O_add:                 left += right; break;
       case O_subtract:            left -= right; break;
       case O_multiply:            left *= right; break;
       case O_divide:
         if (right == 0)
           return 0;
         left = (offsetT) left / (offsetT) right;
         break;
       case O_modulus:
         if (right == 0)
           return 0;
         left = (offsetT) left % (offsetT) right;
         break;
       case O_left_shift:          left <<= right; break;
       case O_right_shift:         left >>= right; break;
       case O_bit_inclusive_or:    left |= right; break;
       case O_bit_or_not:          left |= ~right; break;
       case O_bit_exclusive_or:    left ^= right; break;
       case O_bit_and:                    left &= right; break;
       case O_eq:
       case O_ne:
         left = (left == right
                && seg_left == seg_right
                && (finalize_syms || frag_left == frag_right)
                && (seg_left != undefined_section
                    || add_symbol == op_symbol)
                ? ~ (valueT) 0 : 0);
         if (op == O_ne)
           left = ~left;
         break;
       case O_lt:
         left = (offsetT) left <  (offsetT) right ? ~ (valueT) 0 : 0;
         break;
       case O_le:
         left = (offsetT) left <= (offsetT) right ? ~ (valueT) 0 : 0;
         break;
       case O_ge:
         left = (offsetT) left >= (offsetT) right ? ~ (valueT) 0 : 0;
         break;
       case O_gt:
         left = (offsetT) left >  (offsetT) right ? ~ (valueT) 0 : 0;
         break;
       case O_logical_and:  left = left && right; break;
       case O_logical_or:   left = left || right; break;
       default:             abort ();
       }

      op = O_constant;
      break;
    }

  if (op == O_symbol)
    {
      if (seg_left == absolute_section)
       op = O_constant;
      else if (seg_left == reg_section && final_val == 0)
       op = O_register;
      else if (add_symbol != expressionP->X_add_symbol)
       final_val += left;
      expressionP->X_add_symbol = add_symbol;
    }
  expressionP->X_op = op;

  if (op == O_constant || op == O_register)
    final_val += left;
  expressionP->X_add_number = final_val;

  return 1;
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

const char EXP_CHARS[]

Definition at line 223 of file tc-alpha.c.

Definition at line 58 of file expr.c.

const char FLT_CHARS[]

Definition at line 228 of file tc-alpha.c.

Definition at line 178 of file expr.c.

Initial value:
 {
  &generic_bignum[6],              
  &generic_bignum[SIZE_OF_LARGE_NUMBER + 6 - 1], 
  0,                        
  0,                        
  0                         
}

Definition at line 180 of file expr.c.

const operatorT op_encoding[256] [static]

Definition at line 1391 of file expr.c.

operator_rankT op_rank[] [static]

Definition at line 1435 of file expr.c.