1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
|
/* expr.h -> header file for expr.c
Copyright (C) 1987-2024 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 3, 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, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
/* By popular demand, we define a struct to represent an expression.
This will no doubt mutate as expressions become baroque.
Currently, we support expressions like "foo OP bar + 42". In other
words we permit a (possibly undefined) symbol, a (possibly
undefined) symbol and the operation used to combine the symbols,
and an (absolute) augend. RMS says this is so we can have 1-pass
assembly for any compiler emissions, and a 'case' statement might
emit 'undefined1 - undefined2'.
The type of an expression used to be stored as a segment. That got
confusing because it overloaded the concept of a segment. I added
an operator field, instead. */
/* This is the type of an expression. The operator types are also
used while parsing an expression.
NOTE: This enumeration must match the op_rank array in expr.c. */
typedef enum
{
/* An illegal expression. */
O_illegal,
/* A nonexistent expression. */
O_absent,
/* X_add_number (a constant expression). */
O_constant,
/* X_add_symbol + X_add_number. */
O_symbol,
/* X_add_symbol + X_add_number - the base address of the image. */
O_symbol_rva,
/* The section index of X_add_symbol. */
O_secidx,
/* A register (X_add_number is register number). */
O_register,
/* A big value. If X_add_number is negative or 0, the value is in
generic_floating_point_number. Otherwise the value is in
generic_bignum, and X_add_number is the number of LITTLENUMs in
the value. */
O_big,
/* (- X_add_symbol) + X_add_number. */
O_uminus,
/* (~ X_add_symbol) + X_add_number. */
O_bit_not,
/* (! X_add_symbol) + X_add_number. */
O_logical_not,
/* (X_add_symbol * X_op_symbol) + X_add_number. */
O_multiply,
/* (X_add_symbol / X_op_symbol) + X_add_number. */
O_divide,
/* (X_add_symbol % X_op_symbol) + X_add_number. */
O_modulus,
/* (X_add_symbol << X_op_symbol) + X_add_number. */
O_left_shift,
/* (X_add_symbol >> X_op_symbol) + X_add_number. */
O_right_shift,
/* (X_add_symbol | X_op_symbol) + X_add_number. */
O_bit_inclusive_or,
/* (X_add_symbol |~ X_op_symbol) + X_add_number. */
O_bit_or_not,
/* (X_add_symbol ^ X_op_symbol) + X_add_number. */
O_bit_exclusive_or,
/* (X_add_symbol & X_op_symbol) + X_add_number. */
O_bit_and,
/* (X_add_symbol + X_op_symbol) + X_add_number. */
O_add,
/* (X_add_symbol - X_op_symbol) + X_add_number. */
O_subtract,
/* (X_add_symbol == X_op_symbol) + X_add_number. */
O_eq,
/* (X_add_symbol != X_op_symbol) + X_add_number. */
O_ne,
/* (X_add_symbol < X_op_symbol) + X_add_number. */
O_lt,
/* (X_add_symbol <= X_op_symbol) + X_add_number. */
O_le,
/* (X_add_symbol >= X_op_symbol) + X_add_number. */
O_ge,
/* (X_add_symbol > X_op_symbol) + X_add_number. */
O_gt,
/* (X_add_symbol && X_op_symbol) + X_add_number. */
O_logical_and,
/* (X_add_symbol || X_op_symbol) + X_add_number. */
O_logical_or,
/* X_op_symbol [ X_add_symbol ] */
O_index,
/* machine dependent operators */
O_md1, O_md2, O_md3, O_md4, O_md5, O_md6, O_md7, O_md8,
O_md9, O_md10, O_md11, O_md12, O_md13, O_md14, O_md15, O_md16,
O_md17, O_md18, O_md19, O_md20, O_md21, O_md22, O_md23, O_md24,
O_md25, O_md26, O_md27, O_md28, O_md29, O_md30, O_md31, O_md32,
/* this must be the largest value */
O_max
} operatorT;
typedef struct expressionS
{
/* The main symbol. */
symbolS *X_add_symbol;
/* The second symbol, if needed. */
symbolS *X_op_symbol;
/* A number to add. */
offsetT X_add_number;
/* The type of the expression. We can't assume that an arbitrary
compiler can handle a bitfield of enum type. FIXME: We could
check this using autoconf. */
#ifdef __GNUC__
operatorT X_op : 8;
#else
unsigned char X_op;
#endif
/* Non-zero if X_add_number should be regarded as unsigned. This is
only valid for O_constant expressions. It is only used when an
O_constant must be extended into a bignum (i.e., it is not used
when performing arithmetic on these values).
FIXME: This field is not set very reliably. */
unsigned int X_unsigned : 1;
/* This is used to implement "word size + 1 bit" arithmetic, so that e.g.
expressions used with .sleb128 directives can use the full range available
for an unsigned word, but can also properly represent all values of a
signed word. */
unsigned int X_extrabit : 1;
/* 7 additional bits can be defined if needed. */
/* Machine dependent field */
unsigned short X_md;
} expressionS;
enum expr_mode
{
expr_evaluate,
expr_normal,
expr_defer
};
/* "result" should be type (expressionS *). */
#define expression(result) expr (0, result, expr_normal)
#define expression_and_evaluate(result) expr (0, result, expr_evaluate)
#define deferred_expression(result) expr (0, result, expr_defer)
/* If an expression is O_big, look here for its value. These common
data may be clobbered whenever expr() is called. */
/* Flonums returned here. Big enough to hold most precise flonum. */
extern FLONUM_TYPE generic_floating_point_number;
/* Bignums returned here. */
extern LITTLENUM_TYPE generic_bignum[];
/* Number of littlenums in above. */
#define SIZE_OF_LARGE_NUMBER (20)
typedef char operator_rankT;
extern char get_symbol_name (char **);
extern char restore_line_pointer (char);
extern void expr_begin (void);
extern void expr_end (void);
extern void expr_set_precedence (void);
extern void expr_set_rank (operatorT, operator_rankT);
extern void add_to_result (expressionS *, offsetT, int);
extern void subtract_from_result (expressionS *, offsetT, int);
extern segT expr (int, expressionS *, enum expr_mode);
extern unsigned int get_single_number (void);
extern symbolS *make_expr_symbol (const expressionS * expressionP);
extern int expr_symbol_where (symbolS *, const char **, unsigned int *);
extern void current_location (expressionS *);
extern symbolS *expr_build_uconstant (offsetT);
extern symbolS *expr_build_dot (void);
extern uint32_t generic_bignum_to_int32 (void);
extern uint64_t generic_bignum_to_int64 (void);
extern int resolve_expression (expressionS *);
extern void resolve_register (expressionS *);
extern bool literal_prefix_dollar_hex;
|