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