1/*****************************************************************************/
2/* */
3/* exprdesc.c */
4/* */
5/* Expression descriptor structure */
6/* */
7/* */
8/* */
9/* (C) 2002-2010, Ullrich von Bassewitz */
10/* Roemerstrasse 52 */
11/* D-70794 Filderstadt */
12/* EMail: uz@cc65.org */
13/* */
14/* */
15/* This software is provided 'as-is', without any expressed or implied */
16/* warranty. In no event will the authors be held liable for any damages */
17/* arising from the use of this software. */
18/* */
19/* Permission is granted to anyone to use this software for any purpose, */
20/* including commercial applications, and to alter it and redistribute it */
21/* freely, subject to the following restrictions: */
22/* */
23/* 1. The origin of this software must not be misrepresented; you must not */
24/* claim that you wrote the original software. If you use this software */
25/* in a product, an acknowledgment in the product documentation would be */
26/* appreciated but is not required. */
27/* 2. Altered source versions must be plainly marked as such, and must not */
28/* be misrepresented as being the original software. */
29/* 3. This notice may not be removed or altered from any source */
30/* distribution. */
31/* */
32/*****************************************************************************/
33
34
35
36/* common */
37#include "check.h"
38#include "strbuf.h"
39
40/* cc65 */
41#include "asmlabel.h"
42#include "datatype.h"
43#include "error.h"
44#include "exprdesc.h"
45#include "stackptr.h"
46#include "symentry.h"
47
48
49
50/*****************************************************************************/
51/* Code */
52/*****************************************************************************/
53
54
55
56ExprDesc* ED_Init (ExprDesc* Expr)
57/* Initialize an ExprDesc */
58{
59 Expr->Sym = 0;
60 Expr->Type = 0;
61 Expr->Flags = 0;
62 Expr->Name = 0;
63 Expr->IVal = 0;
64 Expr->FVal = FP_D_Make (0.0);
65 Expr->LVal = 0;
66 Expr->BitOffs = 0;
67 Expr->BitWidth = 0;
68 return Expr;
69}
70
71
72
73void ED_MakeBitField (ExprDesc* Expr, unsigned BitOffs, unsigned BitWidth)
74/* Make this expression a bit field expression */
75{
76 Expr->Flags |= E_BITFIELD;
77 Expr->BitOffs = BitOffs;
78 Expr->BitWidth = BitWidth;
79}
80
81
82
83void ED_SetCodeRange (ExprDesc* Expr, const CodeMark* Start, const CodeMark* End)
84/* Set the code range for this expression */
85{
86 Expr->Flags |= E_HAVE_MARKS;
87 Expr->Start = *Start;
88 Expr->End = *End;
89}
90
91
92
93int ED_CodeRangeIsEmpty (const ExprDesc* Expr)
94/* Return true if no code was output for this expression */
95{
96 /* We must have code marks */
97 PRECONDITION (Expr->Flags & E_HAVE_MARKS);
98
99 return CodeRangeIsEmpty (&Expr->Start, &Expr->End);
100}
101
102
103
104const char* ED_GetLabelName (const ExprDesc* Expr, long Offs)
105/* Return the assembler label name of the given expression. Beware: This
106** function may use a static buffer, so the name may get "lost" on the second
107** call to the function.
108*/
109{
110 static StrBuf Buf = STATIC_STRBUF_INITIALIZER;
111
112 /* Expr may have it's own offset, adjust Offs accordingly */
113 Offs += Expr->IVal;
114
115 /* Generate a label depending on the location */
116 switch (ED_GetLoc (Expr)) {
117
118 case E_LOC_ABS:
119 /* Absolute: numeric address or const */
120 SB_Printf (&Buf, "$%04X", (int)(Offs & 0xFFFF));
121 break;
122
123 case E_LOC_GLOBAL:
124 case E_LOC_STATIC:
125 /* Global or static variable */
126 if (Offs) {
127 SB_Printf (&Buf, "%s%+ld", SymGetAsmName (Expr->Sym), Offs);
128 } else {
129 SB_Printf (&Buf, "%s", SymGetAsmName (Expr->Sym));
130 }
131 break;
132
133 case E_LOC_REGISTER:
134 /* Register variable */
135 SB_Printf (&Buf, "regbank+%u", (unsigned)((Offs + Expr->Name) & 0xFFFFU));
136 break;
137
138 case E_LOC_LITERAL:
139 /* Literal in the literal pool */
140 if (Offs) {
141 SB_Printf (&Buf, "%s%+ld", LocalLabelName (Expr->Name), Offs);
142 } else {
143 SB_Printf (&Buf, "%s", LocalLabelName (Expr->Name));
144 }
145 break;
146
147 default:
148 Internal ("Invalid location in ED_GetLabelName: 0x%04X", ED_GetLoc (Expr));
149 }
150
151 /* Return a pointer to the static buffer */
152 return SB_GetConstBuf (&Buf);
153}
154
155
156
157int ED_GetStackOffs (const ExprDesc* Expr, int Offs)
158/* Get the stack offset of an address on the stack in Expr taking into account
159** an additional offset in Offs.
160*/
161{
162 PRECONDITION (ED_IsLocStack (Expr));
163 Offs += ((int) Expr->IVal) - StackPtr;
164 CHECK (Offs >= 0); /* Cannot handle negative stack offsets */
165 return Offs;
166}
167
168
169
170ExprDesc* ED_MakeConstAbs (ExprDesc* Expr, long Value, Type* Type)
171/* Make Expr an absolute const with the given value and type. */
172{
173 Expr->Sym = 0;
174 Expr->Type = Type;
175 Expr->Flags = E_LOC_ABS | E_RTYPE_RVAL | (Expr->Flags & E_HAVE_MARKS);
176 Expr->Name = 0;
177 Expr->IVal = Value;
178 Expr->FVal = FP_D_Make (0.0);
179 return Expr;
180}
181
182
183
184ExprDesc* ED_MakeConstAbsInt (ExprDesc* Expr, long Value)
185/* Make Expr a constant integer expression with the given value */
186{
187 Expr->Sym = 0;
188 Expr->Type = type_int;
189 Expr->Flags = E_LOC_ABS | E_RTYPE_RVAL | (Expr->Flags & E_HAVE_MARKS);
190 Expr->Name = 0;
191 Expr->IVal = Value;
192 Expr->FVal = FP_D_Make (0.0);
193 return Expr;
194}
195
196
197
198ExprDesc* ED_MakeRValExpr (ExprDesc* Expr)
199/* Convert Expr into a rvalue which is in the primary register without an
200** offset.
201*/
202{
203 Expr->Sym = 0;
204 Expr->Flags &= ~(E_MASK_LOC | E_MASK_RTYPE | E_BITFIELD | E_NEED_TEST | E_CC_SET);
205 Expr->Flags |= (E_LOC_EXPR | E_RTYPE_RVAL);
206 Expr->Name = 0;
207 Expr->IVal = 0; /* No offset */
208 Expr->FVal = FP_D_Make (0.0);
209 return Expr;
210}
211
212
213
214ExprDesc* ED_MakeLValExpr (ExprDesc* Expr)
215/* Convert Expr into a lvalue which is in the primary register without an
216** offset.
217*/
218{
219 Expr->Sym = 0;
220 Expr->Flags &= ~(E_MASK_LOC | E_MASK_RTYPE | E_BITFIELD | E_NEED_TEST | E_CC_SET);
221 Expr->Flags |= (E_LOC_EXPR | E_RTYPE_LVAL);
222 Expr->Name = 0;
223 Expr->IVal = 0; /* No offset */
224 Expr->FVal = FP_D_Make (0.0);
225 return Expr;
226}
227
228
229
230int ED_IsConst (const ExprDesc* Expr)
231/* Return true if the expression denotes a constant of some sort. This can be a
232** numeric constant, the address of a global variable (maybe with offset) or
233** similar.
234*/
235{
236 return ED_IsRVal (Expr) && (Expr->Flags & E_LOC_CONST) != 0;
237}
238
239
240
241int ED_IsConstAbsInt (const ExprDesc* Expr)
242/* Return true if the expression is a constant (numeric) integer. */
243{
244 return (Expr->Flags & (E_MASK_LOC|E_MASK_RTYPE)) == (E_LOC_ABS|E_RTYPE_RVAL) &&
245 IsClassInt (Expr->Type);
246}
247
248
249
250int ED_IsNullPtr (const ExprDesc* Expr)
251/* Return true if the given expression is a NULL pointer constant */
252{
253 return (Expr->Flags & (E_MASK_LOC|E_MASK_RTYPE|E_BITFIELD)) ==
254 (E_LOC_ABS|E_RTYPE_RVAL) &&
255 Expr->IVal == 0 &&
256 IsClassInt (Expr->Type);
257}
258
259
260
261int ED_IsBool (const ExprDesc* Expr)
262/* Return true of the expression can be treated as a boolean, that is, it can
263** be an operand to a compare operation.
264*/
265{
266 /* Either ints, floats, or pointers can be used in a boolean context */
267 return IsClassInt (Expr->Type) ||
268 IsClassFloat (Expr->Type) ||
269 IsClassPtr (Expr->Type);
270}
271
272
273
274void PrintExprDesc (FILE* F, ExprDesc* E)
275/* Print an ExprDesc */
276{
277 unsigned Flags;
278 char Sep;
279
280 fprintf (F, "Symbol: %s\n", E->Sym? E->Sym->Name : "(none)");
281 if (E->Type) {
282 fprintf (F, "Type: ");
283 PrintType (F, E->Type);
284 fprintf (F, "\nRaw type: ");
285 PrintRawType (F, E->Type);
286 } else {
287 fprintf (F, "Type: (unknown)\n"
288 "Raw type: (unknown)\n");
289 }
290 fprintf (F, "IVal: 0x%08lX\n", E->IVal);
291 fprintf (F, "FVal: %f\n", FP_D_ToFloat (E->FVal));
292
293 Flags = E->Flags;
294 Sep = '(';
295 fprintf (F, "Flags: 0x%04X ", Flags);
296 if (Flags & E_LOC_ABS) {
297 fprintf (F, "%cE_LOC_ABS", Sep);
298 Flags &= ~E_LOC_ABS;
299 Sep = ',';
300 }
301 if (Flags & E_LOC_GLOBAL) {
302 fprintf (F, "%cE_LOC_GLOBAL", Sep);
303 Flags &= ~E_LOC_GLOBAL;
304 Sep = ',';
305 }
306 if (Flags & E_LOC_STATIC) {
307 fprintf (F, "%cE_LOC_STATIC", Sep);
308 Flags &= ~E_LOC_STATIC;
309 Sep = ',';
310 }
311 if (Flags & E_LOC_REGISTER) {
312 fprintf (F, "%cE_LOC_REGISTER", Sep);
313 Flags &= ~E_LOC_REGISTER;
314 Sep = ',';
315 }
316 if (Flags & E_LOC_STACK) {
317 fprintf (F, "%cE_LOC_STACK", Sep);
318 Flags &= ~E_LOC_STACK;
319 Sep = ',';
320 }
321 if (Flags & E_LOC_PRIMARY) {
322 fprintf (F, "%cE_LOC_PRIMARY", Sep);
323 Flags &= ~E_LOC_PRIMARY;
324 Sep = ',';
325 }
326 if (Flags & E_LOC_EXPR) {
327 fprintf (F, "%cE_LOC_EXPR", Sep);
328 Flags &= ~E_LOC_EXPR;
329 Sep = ',';
330 }
331 if (Flags & E_LOC_LITERAL) {
332 fprintf (F, "%cE_LOC_LITERAL", Sep);
333 Flags &= ~E_LOC_LITERAL;
334 Sep = ',';
335 }
336 if (Flags & E_RTYPE_LVAL) {
337 fprintf (F, "%cE_RTYPE_LVAL", Sep);
338 Flags &= ~E_RTYPE_LVAL;
339 Sep = ',';
340 }
341 if (Flags & E_BITFIELD) {
342 fprintf (F, "%cE_BITFIELD", Sep);
343 Flags &= ~E_BITFIELD;
344 Sep = ',';
345 }
346 if (Flags & E_NEED_TEST) {
347 fprintf (F, "%cE_NEED_TEST", Sep);
348 Flags &= ~E_NEED_TEST;
349 Sep = ',';
350 }
351 if (Flags & E_CC_SET) {
352 fprintf (F, "%cE_CC_SET", Sep);
353 Flags &= ~E_CC_SET;
354 Sep = ',';
355 }
356 if (Flags) {
357 fprintf (F, "%c,0x%04X", Sep, Flags);
358 Sep = ',';
359 }
360 if (Sep != '(') {
361 fputc (')', F);
362 }
363 fprintf (F, "\nName: 0x%08lX\n", (unsigned long)E->Name);
364}
365
366
367
368Type* ReplaceType (ExprDesc* Expr, const Type* NewType)
369/* Replace the type of Expr by a copy of Newtype and return the old type string */
370{
371 Type* OldType = Expr->Type;
372 Expr->Type = TypeDup (NewType);
373 return OldType;
374}
375