home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 5
/
FreshFish_July-August1994.bin
/
bbs
/
gnu
/
gas-1.38-src.lha
/
src
/
amiga
/
gas-1.38
/
expr.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-09-09
|
31KB
|
981 lines
/* expr.c -operands, expressions-
Copyright (C) 1987 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GAS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GAS; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/*
* This is really a branch office of as-read.c. I split it out to clearly
* distinguish the world of expressions from the world of statements.
* (It also gives smaller files to re-compile.)
* Here, "operand"s are of expressions, not instructions.
*/
#include <ctype.h>
#include "as.h"
#include "flonum.h"
#include "read.h"
#include "struc-symbol.h"
#include "expr.h"
#include "obstack.h"
#include "symbols.h"
static void clean_up_expression(); /* Internal. */
extern const char EXP_CHARS[]; /* JF hide MD floating pt stuff all the same place */
extern const char FLT_CHARS[];
#ifdef SUN_ASM_SYNTAX
extern int local_label_defined[];
#endif
/*
* Build any floating-point literal here.
* Also build any bignum literal here.
*/
/* LITTLENUM_TYPE generic_buffer [6]; /* JF this is a hack */
/* Seems atof_machine can backscan through generic_bignum and hit whatever
happens to be loaded before it in memory. And its way too complicated
for me to fix right. Thus a hack. JF: Just make generic_bignum bigger,
and never write into the early words, thus they'll always be zero.
I hate Dean's floating-point code. Bleh.
*/
LITTLENUM_TYPE generic_bignum [SIZE_OF_LARGE_NUMBER+6];
FLONUM_TYPE generic_floating_point_number =
{
& generic_bignum [6], /* low (JF: Was 0) */
& generic_bignum [SIZE_OF_LARGE_NUMBER+6 - 1], /* high JF: (added +6) */
0, /* leader */
0, /* exponent */
0 /* sign */
};
/* If nonzero, we've been asked to assemble nan, +inf or -inf */
int generic_floating_point_magic;
/*
* Summary of operand().
*
* in: Input_line_pointer points to 1st char of operand, which may
* be a space.
*
* out: A expressionS. X_seg determines how to understand the rest of the
* expressionS.
* The operand may have been empty: in this case X_seg == SEG_NONE.
* Input_line_pointer -> (next non-blank) char after operand.
*
*/
static segT
operand (expressionP)
register expressionS * expressionP;
{
register char c;
register char *name; /* points to name of symbol */
register struct symbol * symbolP; /* Points to symbol */
extern const char hex_value[]; /* In hex_value.c */
char *local_label_name();
SKIP_WHITESPACE(); /* Leading whitespace is part of operand. */
c = * input_line_pointer ++; /* Input_line_pointer -> past char in c. */
if (isdigit(c))
{
register valueT number; /* offset or (absolute) value */
register short int digit; /* value of next digit in current radix */
/* invented for humans only, hope */
/* optimising compiler flushes it! */
register short int radix; /* 8, 10 or 16 */
/* 0 means we saw start of a floating- */
/* point constant. */
register short int maxdig;/* Highest permitted digit value. */
register int too_many_digits; /* If we see >= this number of */
/* digits, assume it is a bignum. */
register char * digit_2; /* -> 2nd digit of number. */
int small; /* TRUE if fits in 32 bits. */
if (c=='0')
{ /* non-decimal radix */
if ((c = * input_line_pointer ++)=='x' || c=='X')
{
c = * input_line_pointer ++; /* read past "0x" or "0X" */
maxdig = radix = 16;
too_many_digits = 9;
}
else
{
/* If it says '0f' and the line ends or it DOESN'T look like
a floating point #, its a local label ref. DTRT */
if(c=='f' && (! *input_line_pointer ||
(!index("+-.0123456789",*input_line_pointer) &&
!index(EXP_CHARS,*input_line_pointer))))
{
maxdig = radix = 10;
too_many_digits = 11;
c='0';
input_line_pointer-=2;
}
else if (c && index (FLT_CHARS,c))
{
radix = 0; /* Start of floating-point constant. */
/* input_line_pointer -> 1st char of number. */
expressionP -> X_add_number = - (isupper(c) ? tolower(c) : c);
}
else
{ /* By elimination, assume octal radix. */
radix = 8;
maxdig = 10; /* Un*x sux. Compatibility. */
too_many_digits = 11;
}
}
/* c == char after "0" or "0x" or "0X" or "0e" etc.*/
}
else
{
maxdig = radix = 10;
too_many_digits = 11;
}
if (radix)
{ /* Fixed-point integer constant. */
/* 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.
*/
digit_2 = 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 - digit_2 < too_many_digits;
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 int carry;
leader = generic_bignum;
generic_bignum [0] = 0;
generic_bignum [1] = 0;
/* We could just use digit_2, but lets be mnemonic. */
input_line_pointer = -- digit_2; /* -> 1st digit. */
c = *input_line_pointer ++;
for (; (carry = hex_value [c]) < maxdig; c = * input_line_pointer ++)
{
for (pointer = generic_bignum;
pointer <= leader;
pointer ++)
{
long int 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( BITS_PER_INT == 32 );
know( LITTLENUM_NUMBER_OF_BITS == 16 );
/* Hence the constant "2" in the next line. */
if (leader < generic_bignum + 2)
{ /* Will fit into 32 bits. */
number =
( (generic_bignum [1] & LITTLENUM_MASK) << LITTLENUM_NUMBER_OF_BITS )
| (generic_bignum [0] & LITTLENUM_MASK);
small = TRUE;
}
else
{
number = leader - generic_bignum + 1; /* Number of littlenums in the bignum. */
}
}
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 (number<10)
{
#ifdef SUN_ASM_SYNTAX
if (c=='b' || (c=='$' && local_lab