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 */
61static const char* SymTab[0x10000];
62
63
64
65/*****************************************************************************/
66/* Code */
67/*****************************************************************************/
68
69
70
71static 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
83static 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
112void 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
120void AddExtLabel (unsigned Addr, const char* Name)
121/* Add an external label */
122{
123 AddLabel (Addr, atExtLabel, Name);
124}
125
126
127
128void AddUnnamedLabel (unsigned Addr)
129/* Add an unnamed label */
130{
131 AddLabel (Addr, atUnnamedLabel, 0);
132}
133
134
135
136void 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
161static 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
199void 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
210void 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
221int 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
230int 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
244const 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
263const 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
336void 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
365static 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
387void 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}
415