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