]> git.sur5r.net Git - cc65/blob - src/da65/labels.c
Changes due to code review.
[cc65] / src / da65 / labels.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 labels.c                                  */
4 /*                                                                           */
5 /*                         Label management for da65                         */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2006-2007 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 #include <stdio.h>
37 #include <string.h>
38
39 /* common */
40 #include "xmalloc.h"
41 #include "xsprintf.h"
42
43 /* da65 */
44 #include "attrtab.h"
45 #include "code.h"
46 #include "comments.h"
47 #include "error.h"
48 #include "global.h"
49 #include "labels.h"
50 #include "output.h"
51
52
53
54 /*****************************************************************************/
55 /*                                   Data                                    */
56 /*****************************************************************************/
57
58
59
60 /* Symbol table */
61 static const char* SymTab[0x10000];
62
63
64
65 /*****************************************************************************/
66 /*                                   Code                                    */
67 /*****************************************************************************/
68
69
70
71 static const char* MakeLabelName (unsigned Addr)
72 /* Make the default label name from the given address and return it in a
73 ** static buffer.
74 */
75 {
76     static char LabelBuf [32];
77     xsprintf (LabelBuf, sizeof (LabelBuf), "L%04X", Addr);
78     return LabelBuf;
79 }
80
81
82
83 static void AddLabel (unsigned Addr, attr_t Attr, const char* Name)
84 /* Add a label */
85 {
86     /* Get an existing label attribute */
87     attr_t ExistingAttr = GetLabelAttr (Addr);
88
89     /* Must not have two symbols for one address */
90     if (ExistingAttr != atNoLabel) {
91         /* Allow redefinition if identical. Beware: Unnamed labels don't
92         ** have a name (you guessed that, didn't you?).
93         */
94         if (ExistingAttr == Attr &&
95             ((Name == 0 && SymTab[Addr] == 0) ||
96              (Name != 0 && SymTab[Addr] != 0 &&
97              strcmp (SymTab[Addr], Name) == 0))) {
98             return;
99         }
100         Error ("Duplicate label for address $%04X: %s/%s", Addr, SymTab[Addr], Name);
101     }
102
103     /* Create a new label (xstrdup will return NULL if input NULL) */
104     SymTab[Addr] = xstrdup (Name);
105
106     /* Remember the attribute */
107     MarkAddr (Addr, Attr);
108 }
109
110
111
112 void AddIntLabel (unsigned Addr)
113 /* Add an internal label using the address to generate the name. */
114 {
115     AddLabel (Addr, atIntLabel, MakeLabelName (Addr));
116 }
117
118
119
120 void AddExtLabel (unsigned Addr, const char* Name)
121 /* Add an external label */
122 {
123     AddLabel (Addr, atExtLabel, Name);
124 }
125
126
127
128 void AddUnnamedLabel (unsigned Addr)
129 /* Add an unnamed label */
130 {
131     AddLabel (Addr, atUnnamedLabel, 0);
132 }
133
134
135
136 void AddDepLabel (unsigned Addr, attr_t Attr, const char* BaseName, unsigned Offs)
137 /* Add a dependent label at the given address using "basename+Offs" as the new
138 ** name.
139 */
140 {
141     /* Allocate memory for the dependent label name */
142     unsigned NameLen = strlen (BaseName);
143     char*    DepName = xmalloc (NameLen + 7);   /* "+$ABCD\0" */
144
145     /* Create the new name in the buffer */
146     if (UseHexOffs) {
147         sprintf (DepName, "%s+$%02X", BaseName, Offs);
148     } else {
149         sprintf (DepName, "%s+%u", BaseName, Offs);
150     }
151
152     /* Define the labels */
153     AddLabel (Addr, Attr | atDepLabel, DepName);
154
155     /* Free the name buffer */
156     xfree (DepName);
157 }
158
159
160
161 static void AddLabelRange (unsigned Addr, attr_t Attr,
162                            const char* Name, unsigned Count)
163 /* Add a label for a range. The first entry gets the label "Name" while the
164 ** others get "Name+offs".
165 */
166 {
167     /* Define the label */
168     AddLabel (Addr, Attr, Name);
169
170     /* Define dependent labels if necessary */
171     if (Count > 1) {
172         unsigned Offs;
173
174         /* Setup the format string */
175         const char* Format = UseHexOffs? "$%02X" : "%u";
176
177         /* Allocate memory for the dependent label names */
178         unsigned NameLen = strlen (Name);
179         char*    DepName = xmalloc (NameLen + 7);       /* "+$ABCD" */
180         char*    DepOffs = DepName + NameLen + 1;
181
182         /* Copy the original name into the buffer */
183         memcpy (DepName, Name, NameLen);
184         DepName[NameLen] = '+';
185
186         /* Define the labels */
187         for (Offs = 1; Offs < Count; ++Offs) {
188             sprintf (DepOffs, Format, Offs);
189             AddLabel (Addr + Offs, Attr | atDepLabel, DepName);
190         }
191
192         /* Free the name buffer */
193         xfree (DepName);
194     }
195 }
196
197
198
199 void AddIntLabelRange (unsigned Addr, const char* Name, unsigned Count)
200 /* Add an internal label for a range. The first entry gets the label "Name"
201 ** while the others get "Name+offs".
202 */
203 {
204     /* Define the label range */
205     AddLabelRange (Addr, atIntLabel, Name, Count);
206 }
207
208
209
210 void AddExtLabelRange (unsigned Addr, const char* Name, unsigned Count)
211 /* Add an external label for a range. The first entry gets the label "Name"
212 ** while the others get "Name+offs".
213 */
214 {
215     /* Define the label range */
216     AddLabelRange (Addr, atExtLabel, Name, Count);
217 }
218
219
220
221 int HaveLabel (unsigned Addr)
222 /* Check if there is a label for the given address */
223 {
224     /* Check for a label */
225     return (GetLabelAttr (Addr) != atNoLabel);
226 }
227
228
229
230 int MustDefLabel (unsigned Addr)
231 /* Return true if we must define a label for this address, that is, if there
232 ** is a label at this address, and it is an external or internal label.
233 */
234 {
235     /* Get the label attribute */
236     attr_t A = GetLabelAttr (Addr);
237
238     /* Check for an internal, external, or unnamed label */
239     return (A == atExtLabel || A == atIntLabel || A == atUnnamedLabel);
240 }
241
242
243
244 const char* GetLabelName (unsigned Addr)
245 /* Return the label name for an address */
246 {
247     /* Get the label attribute */
248     attr_t A = GetLabelAttr (Addr);
249
250     /* Special case unnamed labels, because these don't have a named stored in
251     ** the symbol table to save space.
252     */
253     if (A == atUnnamedLabel) {
254         return "";
255     } else {
256         /* Return the label if any */
257         return SymTab[Addr];
258     }
259 }
260
261
262
263 const char* GetLabel (unsigned Addr, unsigned RefFrom)
264 /* Return the label name for an address, as it is used in a label reference.
265 ** RefFrom is the address the label is referenced from. This is needed in case
266 ** of unnamed labels, to determine the name.
267 */
268 {
269     static const char* const FwdLabels[] = {
270         ":+", ":++", ":+++", ":++++", ":+++++", ":++++++", ":+++++++",
271         ":++++++++", ":+++++++++", ":++++++++++"
272     };
273     static const char* const BackLabels[] = {
274         ":-", ":--", ":---", ":----", ":-----", ":------", ":-------",
275         ":--------", ":---------", ":----------"
276     };
277
278     /* Get the label attribute */
279     attr_t A = GetLabelAttr (Addr);
280
281     /* Special case unnamed labels, because these don't have a named stored in
282     ** the symbol table to save space.
283     */
284     if (A == atUnnamedLabel) {
285
286         unsigned Count = 0;
287
288         /* Search forward or backward depending in which direction the label
289         ** is.
290         */
291         if (Addr <= RefFrom) {
292             /* Search backwards */
293             unsigned I = RefFrom;
294             while (Addr < I) {
295                 --I;
296                 A = GetLabelAttr (I);
297                 if (A == atUnnamedLabel) {
298                     ++Count;
299                     if (Count >= sizeof (BackLabels) / sizeof (BackLabels[0])) {
300                         Error ("Too many unnamed labels between label at "
301                                "$%04X and reference at $%04X", Addr, RefFrom);
302                     }
303                 }
304             }
305
306             /* Return the label name */
307             return BackLabels[Count-1];
308
309         } else {
310             /* Search forwards */
311             unsigned I = RefFrom;
312             while (Addr > I) {
313                 ++I;
314                 A = GetLabelAttr (I);
315                 if (A == atUnnamedLabel) {
316                     ++Count;
317                     if (Count >= sizeof (FwdLabels) / sizeof (FwdLabels[0])) {
318                         Error ("Too many unnamed labels between label at "
319                                "$%04X and reference at $%04X", Addr, RefFrom);
320                     }
321                 }
322             }
323
324             /* Return the label name */
325             return FwdLabels[Count-1];
326         }
327
328     } else {
329         /* Return the label if any */
330         return SymTab[Addr];
331     }
332 }
333
334
335
336 void ForwardLabel (unsigned Offs)
337 /* If necessary, output a forward label, one that is within the next few
338 ** bytes and is therefore output as "label = * + x".
339 */
340 {
341     /* Calculate the actual address */
342     unsigned long Addr = PC + Offs;
343
344     /* Get the type of the label */
345     attr_t A = GetLabelAttr (Addr);
346
347     /* If there is no label, or just a dependent one, bail out */
348     if (A == atNoLabel || (A & atDepLabel) != 0) {
349         return;
350     }
351
352     /* An unnamed label cannot be output as a forward declaration, so this is
353     ** an error.
354     */
355     if (A == atUnnamedLabel) {
356         Error ("Cannot define unnamed label at address $%04lX", Addr);
357     }
358
359     /* Output the label */
360     DefForward (GetLabelName (Addr), GetComment (Addr), Offs);
361 }
362
363
364
365 static void DefOutOfRangeLabel (unsigned long Addr)
366 /* Define one label that is outside code range. */
367 {
368     switch (GetLabelAttr (Addr)) {
369
370         case atIntLabel:
371         case atExtLabel:
372             DefConst (SymTab[Addr], GetComment (Addr), Addr);
373             break;
374
375         case atUnnamedLabel:
376             Error ("Cannot define unnamed label at address $%04lX", Addr);
377             break;
378
379         default:
380             break;
381
382     }
383 }
384
385
386
387 void DefOutOfRangeLabels (void)
388 /* Output any labels that are out of the loaded code range */
389 {
390     unsigned long Addr;
391
392     SeparatorLine ();
393
394     /* Low range */
395     Addr = 0;
396     while (Addr < CodeStart) {
397         DefOutOfRangeLabel (Addr++);
398     }
399
400     /* Skip areas in code range */
401     while (Addr <= CodeEnd) {
402         if (GetStyleAttr (Addr) == atSkip) {
403             DefOutOfRangeLabel (Addr);
404         }
405         ++Addr;
406     }
407
408     /* High range */
409     while (Addr < 0x10000) {
410         DefOutOfRangeLabel (Addr++);
411     }
412
413     SeparatorLine ();
414 }