#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include "stuff/rnd.h"
#include "as.h"
#include "flonum.h"
#include "struc-symbol.h"
#include "expr.h"
#include "read.h"
#include "obstack.h"
#include "symbols.h"
#include "hex_value.h"
#include "md.h"
#include "messages.h"
#include "sections.h"
typedef char operator_rankT;
typedef enum {
O_illegal,
O_multiply,
O_divide,
O_modulus,
O_add,
O_subtract,
O_right_shift,
O_left_shift,
O_less_than,
O_greater_than,
O_less_than_or_equal,
O_greater_than_or_equal,
O_equal,
O_not_equal,
O_bit_and,
O_bit_exclusive_or,
O_bit_inclusive_or,
O_bit_or_not,
O_logical_and,
O_logical_or,
two_char_operator
} operatorT;
static segT expr(
operator_rankT rank,
expressionS *resultP);
static segT operand(
expressionS *expressionP);
static void clean_up_expression(
expressionS *expressionP);
static segT expr_part(
struct symbol **symbol_1_PP,
struct symbol *symbol_2_P);
static operatorT two_char_op_encoding(
char first_op_char);
static void ignore_c_ll_or_ull(
char c);
symbolS *
make_expr_symbol (expressionS *expressionP)
{
#ifdef NOTYET
expressionS zero;
#endif
symbolS *symbolP;
#ifdef NOTYET
struct expr_symbol_line *n;
#endif
if (expressionP->X_op == O_symbol
&& expressionP->X_add_number == 0)
return expressionP->X_add_symbol;
#ifndef NOTYET
abort ();
#else
if (expressionP->X_op == O_big)
{
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;
}
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;
#endif
return symbolP;
}
symbolS *
expr_build_uconstant (offsetT value)
{
expressionS e;
e.X_op = O_constant;
e.X_add_number = value;
e.X_unsigned = 1;
return make_expr_symbol (&e);
}
char *seg_name[] = {
"absolute",
"section",
"difference",
"unknown",
"absent",
"bignum/flonum",
};
#ifdef SUSPECT
static int seg_N_TYPE[] = {
N_ABS,
N_SECT,
-1,
N_UNDF,
-1,
-1
};
#endif
segT N_TYPE_seg[] =
{
SEG_UNKNOWN, -1, SEG_ABSOLUTE, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
SEG_SECT, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
};
LITTLENUM_TYPE generic_bignum[SIZE_OF_LARGE_NUMBER + 6] = { 0 };
FLONUM_TYPE generic_floating_point_number = {
&generic_bignum[6],
&generic_bignum[SIZE_OF_LARGE_NUMBER + 6 - 1],
0,
0,
0
};
static int op_size [] =
{ 0, 1, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2 };
static operator_rankT op_rank [] =
{ 0,10,10,10, 9, 9, 8, 8, 7, 7, 7, 7, 6, 6, 5, 4, 3, 3, 2, 1 };
#define __ O_illegal
static const operatorT op_encoding [256] = {
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
__, two_char_operator, __, __, __, O_modulus, two_char_operator, __,
__, __, O_multiply, O_add, __, O_subtract, __, O_divide,
__, __, __, __, __, __, __, __,
__, __, __, __, two_char_operator, two_char_operator, two_char_operator, __,
__, __, __, __, __, __, __, __,
__, __, __, __, __, __, __, __,
__, __, __, __, __, __, __, __,
__, __, __, __, __, __, O_bit_exclusive_or, __,
__, __, __, __, __, __, __, __,
__, __, __, __, __, __, __, __,
__, __, __, __, __, __, __, __,
__, __, __, __, two_char_operator, __, __, __,
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __
};
segT
expression(
expressionS *resultP)
{
segT segment;
segment = expr(0, resultP);
if(segment == SEG_DIFFSECT &&
resultP->X_add_symbol == NULL &&
(resultP->X_subtract_symbol->sy_type & N_TYPE) != N_UNDF){
as_warn("Subtracting symbol \"%s\"(segment\"%s\") is too "
"hard. Absolute segment assumed.",
resultP->X_subtract_symbol->sy_name,
seg_name[(int)N_TYPE_seg[
resultP->X_subtract_symbol->sy_type & N_TYPE]]);
segment = SEG_ABSOLUTE;
}
return(segment);
}
static
segT
expr(
operator_rankT rank,
expressionS *resultP)
{
expressionS right;
operatorT op_left;
char c_left;
operatorT op_right;
char c_right;
know(rank >= 0);
(void)operand(resultP);
know(*input_line_pointer != ' ');
c_left = *input_line_pointer;
op_left = (operatorT)op_encoding[(int)c_left];
if(op_left == two_char_operator)
op_left = two_char_op_encoding(c_left);
while(op_left != O_illegal && op_rank[op_left] > rank){
input_line_pointer += op_size[op_left];
if(SEG_NONE == expr(op_rank[op_left], &right)){
as_warn("Missing operand value assumed absolute 0.");
resultP->X_add_number = 0;
resultP->X_subtract_symbol = NULL;
resultP->X_add_symbol = NULL;
resultP->X_seg = SEG_ABSOLUTE;
}
know(*input_line_pointer != ' ');
c_right = *input_line_pointer;
op_right = (operatorT)op_encoding[(int)c_right];
if(op_right == two_char_operator)
op_right = two_char_op_encoding(c_right);
know(op_right == 0 || op_rank [op_right] <= op_rank[op_left]);
if(resultP->X_seg == SEG_BIG){
as_warn("Left operand of %c is a %s integer 0 assumed",
c_left, resultP->X_add_number > 0 ? "bignum" :
"float");
resultP->X_seg = SEG_ABSOLUTE;
resultP->X_add_symbol = 0;
resultP->X_subtract_symbol = 0;
resultP->X_add_number = 0;
}
if(right.X_seg == SEG_BIG){
as_warn("Right operand of %c is a %s integer 0 assumed",
c_left, right.X_add_number > 0 ? "bignum" :
"float");
right.X_seg = SEG_ABSOLUTE;
right.X_add_symbol = 0;
right.X_subtract_symbol = 0;
right.X_add_number = 0;
}
if(op_left == O_subtract){
struct symbol *symbolP;
right.X_add_number = - right.X_add_number;
symbolP = right.X_add_symbol;
right.X_add_symbol = right.X_subtract_symbol;
right.X_subtract_symbol = symbolP;
if(symbolP){
right.X_seg = SEG_DIFFSECT;
}
op_left = O_add;
}
if(op_left == O_add){
segT seg1;
segT seg2;
know(resultP->X_seg == SEG_SECT ||
resultP->X_seg == SEG_UNKNOWN ||
resultP->X_seg == SEG_DIFFSECT ||
resultP->X_seg == SEG_ABSOLUTE);
know(right.X_seg == SEG_SECT ||
right.X_seg == SEG_UNKNOWN ||
right.X_seg == SEG_DIFFSECT ||
right.X_seg == SEG_ABSOLUTE);
clean_up_expression(&right);
clean_up_expression(resultP);
seg1 = expr_part(&resultP->X_add_symbol,
right.X_add_symbol);
seg2 = expr_part(&resultP->X_subtract_symbol,
right.X_subtract_symbol);
if((int)seg1 == -1 || (int)seg2 == -1){
as_warn("Can't relocate expression. Absolute 0 assumed.");
resultP->X_seg = SEG_ABSOLUTE;
resultP->X_add_number = 0;
}
else{
if(seg2 == SEG_ABSOLUTE){
if(resultP->X_seg != SEG_DIFFSECT)
resultP->X_seg = seg1;
}
else{
know(seg2 != SEG_ABSOLUTE);
know(resultP->X_subtract_symbol);
if(!flagseen['k']){
if(seg1 != SEG_UNKNOWN &&
seg1 != SEG_ABSOLUTE &&
seg2 != SEG_UNKNOWN &&
seg1 != seg2 &&
resultP->X_add_symbol->sy_other !=
resultP->X_subtract_symbol->sy_other){
know(seg1 == SEG_SECT);
know(seg2 == SEG_SECT);
know(resultP->X_add_symbol);
know(resultP->X_subtract_symbol);
as_warn("Expression too complex: "
"forgetting %s - %s",
resultP->X_add_symbol->sy_name,
resultP->X_subtract_symbol->sy_name);
resultP->X_seg = SEG_ABSOLUTE;
}
else{
resultP->X_seg = SEG_DIFFSECT;
}
}
else{
resultP->X_seg = SEG_DIFFSECT;
}
}
}
resultP->X_add_number += right.X_add_number;
clean_up_expression(resultP);
}
else{
if(resultP->X_seg == SEG_UNKNOWN ||
right.X_seg == SEG_UNKNOWN){
as_warn("Can't relocate expression. Absolute 0 assumed.");
resultP->X_seg = SEG_ABSOLUTE;
resultP->X_add_number = 0;
}
else{
try_to_make_absolute(resultP);
try_to_make_absolute(&right);
if(resultP->X_seg == SEG_DIFFSECT &&
right.X_seg == SEG_ABSOLUTE &&
op_left == O_divide &&
right.X_add_number == 2){
resultP->X_sectdiff_divide_by_two = 1;
goto down;
}
resultP->X_subtract_symbol = NULL;
resultP->X_add_symbol = NULL;
if(resultP->X_seg != SEG_ABSOLUTE ||
right.X_seg != SEG_ABSOLUTE){
as_warn("Relocation error. Absolute 0 assumed");
resultP->X_seg = SEG_ABSOLUTE;
resultP->X_add_number = 0;
}
else{
switch(op_left){
case O_bit_inclusive_or:
resultP->X_add_number |= right.X_add_number;
break;
case O_logical_or:
resultP->X_add_number =
resultP->X_add_number || right.X_add_number;
break;
case O_modulus:
if(right.X_add_number){
resultP->X_add_number %=
right.X_add_number;
}
else{
as_warn("Division by 0. 0 assumed.");
resultP->X_add_number = 0;
}
break;
case O_bit_and:
resultP->X_add_number &= right.X_add_number;
break;
case O_logical_and:
resultP->X_add_number =
resultP->X_add_number && right.X_add_number;
break;
case O_multiply:
resultP->X_add_number *= right.X_add_number;
break;
case O_divide:
if(right.X_add_number){
resultP->X_add_number /=
right.X_add_number;
}
else{
as_warn("Division by 0. 0 assumed.");
resultP->X_add_number = 0;
}
break;
case O_left_shift:
resultP->X_add_number <<=
right.X_add_number;
break;
case O_right_shift:
resultP->X_add_number >>=
right.X_add_number;
break;
case O_bit_exclusive_or:
resultP->X_add_number ^= right.X_add_number;
break;
case O_bit_or_not:
resultP->X_add_number |=
~right.X_add_number;
break;
case O_less_than:
resultP->X_add_number =
(resultP->X_add_number <
right.X_add_number);
break;
case O_greater_than:
resultP->X_add_number =
(resultP->X_add_number >
right.X_add_number);
break;
case O_less_than_or_equal:
resultP->X_add_number =
(resultP->X_add_number <=
right.X_add_number);
break;
case O_greater_than_or_equal:
resultP->X_add_number =
(resultP->X_add_number >=
right.X_add_number);
break;
case O_equal:
resultP->X_add_number =
(resultP->X_add_number ==
right.X_add_number);
break;
case O_not_equal:
resultP->X_add_number =
(resultP->X_add_number !=
right.X_add_number);
break;
default:
BAD_CASE( op_left );
break;
}
}
down: ;
}
}
op_left = op_right;
}
return(resultP->X_seg);
}
static
segT
operand(
expressionS *expressionP)
{
char c, q;
char *name;
struct symbol *symbolP;
SKIP_WHITESPACE();
c = *input_line_pointer++;
if(isdigit(c)){
signed_expr_t
number;
int digit;
int radix;
int maxdig;
int too_many_digits;
char *digit_2;
int small;
int force_bignum;
force_bignum = FALSE;
maxdig = 0;
too_many_digits = 0;
if(c == '0'){
c = *input_line_pointer++;
if(c == 'x' || c=='X'){
c = *input_line_pointer++;
maxdig = 16;
radix = 16;
too_many_digits = 9;
}
else if((c == 'b' || c == 'B') &&
(*input_line_pointer != '\0') &&
strchr("0123456789abcdefABCDEF",
*input_line_pointer) != NULL){
force_bignum = TRUE;
c = *input_line_pointer++;
maxdig = 16;
radix = 16;
too_many_digits = 9;
}
else{
if(c == 'f' &&
(*input_line_pointer == '\0' ||
(strchr("+-.0123456789", *input_line_pointer) == NULL &&
strchr(md_EXP_CHARS, *input_line_pointer) == NULL) )){
maxdig = 10;
radix = 10;
too_many_digits = 11;
c = '0';
input_line_pointer -= 2;
}
else if(c != '\0' && strchr(md_FLT_CHARS, c) != NULL){
radix = 0;
expressionP->X_add_number =
- (isupper(c) ? tolower(c) : c);
}
else{
radix = 8;
maxdig = 10;
too_many_digits = 11;
}
}
}
else{
maxdig = 10;
radix = 10;
too_many_digits = 11;
}
too_many_digits *= 2;
if(radix != 0){
digit_2 = input_line_pointer;
for(number = 0;
(digit = hex_value[(int)c]) < maxdig;
c = *input_line_pointer++){
number = number * radix + digit;
}
small = input_line_pointer - digit_2 < too_many_digits;
if(force_bignum == TRUE)
small = FALSE;
if(small == FALSE){
LITTLENUM_TYPE *leader;
LITTLENUM_TYPE *pointer;
int32_t carry;
leader = generic_bignum;
generic_bignum [0] = 0;
input_line_pointer = --digit_2;
c = *input_line_pointer++;
for( ;
(carry = hex_value[(int)c]) < maxdig;
c = * input_line_pointer++){
for(pointer = generic_bignum;
pointer <= leader;
pointer++){
int32_t 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){
*++leader = carry;
}
}
}
know(LITTLENUM_NUMBER_OF_BITS == 16);
if(leader < generic_bignum + 2 && force_bignum == FALSE)
{
number = ((generic_bignum[1] & LITTLENUM_MASK) <<
LITTLENUM_NUMBER_OF_BITS) |
(generic_bignum[0] & LITTLENUM_MASK);
small = TRUE;
}
else{
number = leader - generic_bignum + 1;
}
}
if(small){
if(c == 'b'){
name = fb_label_name((int)number, 0);
symbolP = symbol_table_lookup(name);
if((symbolP != NULL) &&
(symbolP->sy_type & N_TYPE) != N_UNDF){
know((symbolP->sy_type & N_TYPE) == N_SECT);
expressionP->X_add_symbol = symbolP;
expressionP->X_add_number = 0;
expressionP->X_seg = SEG_SECT;
}
else{
as_warn("Backw. ref to unknown label \"%lld\","
"0 assumed.", number);
expressionP->X_add_number = 0;
expressionP->X_seg = SEG_ABSOLUTE;
}
}
else if(c == 'f'){
name = fb_label_name((int)number, 1);
symbolP = symbol_table_lookup(name);
if(symbolP != NULL){
know((symbolP->sy_type & N_TYPE) == N_UNDF ||
(symbolP->sy_type & N_TYPE) == N_SECT);
}
else{
symbolP = symbol_new(name, N_UNDF, 0,0,0,
&zero_address_frag);
symbol_table_insert(symbolP);
}
expressionP->X_add_symbol = symbolP;
expressionP->X_seg = SEG_UNKNOWN;
expressionP->X_subtract_symbol = NULL;
expressionP->X_add_number = 0;
}
else{
ignore_c_ll_or_ull(c);
expressionP->X_add_number = number;
expressionP->X_seg = SEG_ABSOLUTE;
input_line_pointer--;
}
}
else{
ignore_c_ll_or_ull(c);
expressionP->X_add_number = number;
expressionP->X_seg = SEG_BIG;
input_line_pointer--;
}
}
else{
int error_code;
error_code = atof_generic(&input_line_pointer, ".", md_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_seg = SEG_BIG;
know(expressionP->X_add_number < 0);
}
}
#ifdef PPC
else if((c == '.' || c == '$') && !is_part_of_name(*input_line_pointer))
#else
else if(c == '.' && !is_part_of_name(*input_line_pointer))
#endif
{
symbolP = symbol_new("L0\001",
N_SECT,
frchain_now->frch_nsect,
0,
(valueT)(obstack_next_free(&frags) -
frag_now->fr_literal),
frag_now);
symbol_assign_index(symbolP);
expressionP->X_add_number = 0;
expressionP->X_add_symbol = symbolP;
expressionP->X_seg = SEG_SECT;
}
else if(is_name_beginner(c) || c == '"'){
q = c;
if(q == '"')
name = input_line_pointer-- ;
else
name = -- input_line_pointer;
c = get_symbol_end();
symbolP = symbol_table_lookup(name);
if(symbolP != NULL){
segT seg;
seg = N_TYPE_seg[(int)symbolP->sy_type & N_TYPE];
expressionP->X_seg = seg;
if(seg == SEG_ABSOLUTE && symbolP->expression == NULL){
expressionP->X_add_number =
#ifndef ARCH64
(int32_t)
#endif
symbolP->sy_value;
}
else{
expressionP->X_add_number = 0;
expressionP->X_add_symbol = symbolP;
if(symbolP->expression != NULL)
expressionP->X_seg = SEG_DIFFSECT;
}
}
else{
symbolP = symbol_new(name, N_UNDF, 0,0,0, &zero_address_frag);
expressionP->X_add_symbol = symbolP;
expressionP->X_add_number = 0;
expressionP->X_seg = SEG_UNKNOWN;
symbol_table_insert(symbolP);
}
*input_line_pointer = c;
if(q == '"')
input_line_pointer[-1] = '"';
expressionP->X_subtract_symbol = NULL;
}
else if (c == '('){
(void)expression(expressionP);
if(*input_line_pointer++ != ')'){
as_warn("Missing ')' assumed");
input_line_pointer--;
}
}
else if(c == '~' || c == '-' || c == '!'){
switch(operand(expressionP)){
case SEG_ABSOLUTE:
if(c == '-' ){
expressionP->X_add_number = - expressionP->X_add_number;
}
else if(c == '!'){
expressionP->X_add_number = ! expressionP->X_add_number;
}
else{
expressionP->X_add_number = ~ expressionP->X_add_number;
}
break;
case SEG_SECT:
case SEG_UNKNOWN:
if(c == '-'){
expressionP->X_subtract_symbol = expressionP->X_add_symbol;
expressionP->X_add_symbol = 0;
expressionP->X_seg = SEG_DIFFSECT;
break;
}
default:
as_warn("Unary operator %c ignored because bad operand follows",
c);
break;
}
}
else if(c == '\''){
expressionP->X_add_number = *input_line_pointer++;
expressionP->X_seg = SEG_ABSOLUTE;
}
else{
expressionP->X_seg = SEG_NONE;
input_line_pointer--;
}
clean_up_expression(expressionP);
SKIP_WHITESPACE();
know(*input_line_pointer != ' ');
return(expressionP->X_seg);
}
static
void
clean_up_expression(
expressionS *expressionP)
{
switch(expressionP->X_seg){
case SEG_NONE:
expressionP->X_add_symbol = NULL;
expressionP->X_subtract_symbol = NULL;
expressionP->X_add_number = 0;
break;
case SEG_BIG:
case SEG_ABSOLUTE:
expressionP->X_subtract_symbol = NULL;
expressionP->X_add_symbol = NULL;
break;
case SEG_SECT:
case SEG_UNKNOWN:
expressionP->X_subtract_symbol = NULL;
break;
case SEG_DIFFSECT:
if(expressionP->X_subtract_symbol == expressionP->X_add_symbol){
expressionP->X_subtract_symbol = NULL;
expressionP->X_add_symbol = NULL;
expressionP->X_seg = SEG_ABSOLUTE;
}
break;
default:
BAD_CASE(expressionP->X_seg);
break;
}
}
static
segT
expr_part(
struct symbol **symbol_1_PP,
struct symbol *symbol_2_P)
{
segT return_value;
know( (*symbol_1_PP) == NULL ||
((*symbol_1_PP)->sy_type & N_TYPE) == N_SECT ||
((*symbol_1_PP)->sy_type & N_TYPE) == N_UNDF);
know( symbol_2_P == NULL ||
(symbol_2_P->sy_type & N_TYPE) == N_SECT ||
(symbol_2_P->sy_type & N_TYPE) == N_UNDF);
if(*symbol_1_PP != NULL){
if(((*symbol_1_PP)->sy_type & N_TYPE) == N_UNDF){
if(symbol_2_P != NULL){
*symbol_1_PP = NULL;
return_value = -1;
}
else{
return_value = SEG_UNKNOWN;
}
}
else{
if(symbol_2_P != NULL){
if((symbol_2_P->sy_type & N_TYPE) == N_UNDF){
*symbol_1_PP = NULL;
return_value = -1;
}
else{
as_warn("Expression too complex, 2 symbols forgotten: "
"\"%s\" \"%s\"", (*symbol_1_PP)->sy_name,
symbol_2_P->sy_name);
*symbol_1_PP = NULL;
return_value = SEG_ABSOLUTE;
}
}
else{
return_value = N_TYPE_seg[(*symbol_1_PP)->sy_type & N_TYPE];
}
}
}
else{
if(symbol_2_P != NULL){
*symbol_1_PP = symbol_2_P;
return_value = N_TYPE_seg[(symbol_2_P)->sy_type & N_TYPE];
}
else{
return_value = SEG_ABSOLUTE;
}
}
know(return_value == SEG_ABSOLUTE ||
return_value == SEG_SECT ||
return_value == SEG_UNKNOWN ||
return_value == -1);
know((*symbol_1_PP) == NULL ||
((*symbol_1_PP)->sy_type & N_TYPE) ==
seg_N_TYPE[(int)return_value]);
return(return_value);
}
segT
try_to_make_absolute(
expressionS *expressionP)
{
symbolS *add_symbol;
symbolS *subtract_symbol;
if(expressionP->X_seg == SEG_DIFFSECT){
if(flagseen['k'])
goto giveup;
add_symbol = expressionP->X_add_symbol;
if(add_symbol == NULL)
goto giveup;
if((add_symbol->sy_type & N_TYPE) != N_SECT)
goto giveup;
subtract_symbol = expressionP->X_subtract_symbol;
if(subtract_symbol == NULL)
goto giveup;
if((subtract_symbol->sy_type & N_TYPE) != N_SECT)
goto giveup;
if(add_symbol->sy_frag == subtract_symbol->sy_frag){
if(add_symbol->sy_frag != NULL &&
expressionP->X_add_number +
(int)add_symbol->sy_value -
(int)subtract_symbol->sy_value >= 0){
expressionP->X_add_number += add_symbol->sy_value -
subtract_symbol->sy_value;
expressionP->X_seg = SEG_ABSOLUTE;
expressionP->X_add_symbol = NULL;
expressionP->X_subtract_symbol = NULL;
}
}
else{
if(!flagseen['k']){
uint32_t size, fail;
struct frag *frag;
if(add_symbol->sy_frag != NULL &&
subtract_symbol->sy_frag != NULL){
fail = 0;
size = 0;
frag = subtract_symbol->sy_frag;
while(!fail && frag != NULL &&
frag != add_symbol->sy_frag){
if(frag->fr_type == rs_align)
size = rnd(size + frag->fr_fix,
1 << frag->fr_offset);
else if(frag->fr_type == rs_fill)
size += frag->fr_fix +
frag->fr_var * frag->fr_offset;
else
fail = 1;
frag = frag->fr_next;
}
if(!fail && frag == add_symbol->sy_frag){
expressionP->X_add_number = size +
add_symbol->sy_value -
subtract_symbol->sy_value;
expressionP->X_seg = SEG_ABSOLUTE;
expressionP->X_add_symbol = NULL;
expressionP->X_subtract_symbol = NULL;
}
}
}
}
}
giveup:
return(expressionP->X_seg);
}
static
operatorT
two_char_op_encoding(
char first_op_char)
{
char second_op_char;
second_op_char = input_line_pointer[1];
switch(first_op_char){
case '<':
if(second_op_char == '<')
return(O_left_shift);
if(second_op_char == '=')
return(O_less_than_or_equal);
if(second_op_char == '>')
return(O_not_equal);
return(O_less_than);
case '>':
if(second_op_char == '>')
return(O_right_shift);
if(second_op_char == '=')
return(O_greater_than_or_equal);
return(O_greater_than);
case '=':
if(second_op_char == '=')
return(O_equal);
return(O_illegal);
case '!':
if(second_op_char == '=')
return(O_not_equal);
return O_not_equal;
case '&':
if(second_op_char == '&')
return(O_logical_and);
return(O_bit_and);
case '|':
if(second_op_char == '|')
return(O_logical_or);
return(O_bit_inclusive_or);
default:
BAD_CASE(first_op_char);
return O_illegal;
}
}
char
get_symbol_end(
void)
{
register char c;
if(*input_line_pointer == '"'){
input_line_pointer++;
do{
c = *input_line_pointer++ ;
}while(c != '"' && c != '\0' && c != '\n');
if(c == '"'){
*(input_line_pointer - 1) = 0;
c = *input_line_pointer++;
}
}
else{
while(is_part_of_name(c = *input_line_pointer++))
;
}
*--input_line_pointer = 0;
return(c);
}
#include <stdlib.h>
segT S_GET_SEGMENT (symbolS *s)
{
return s->sy_nlist.n_sect;
}
static
void
ignore_c_ll_or_ull(
char c)
{
int charsRead = 0;
if(c != 'U' && c != 'L'){
return;
}
if(c == 'U'){
c = *input_line_pointer++;
charsRead++;
}
if(c == 'L'){
c = *input_line_pointer++;
charsRead++;
}
if(c == 'L'){
c = *input_line_pointer++;
}
else{
input_line_pointer -= charsRead;
}
}