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