1 /*****************************************************************************/
5 /* Label management for da65 */
9 /* (C) 2006-2007 Ullrich von Bassewitz */
10 /* Roemerstrasse 52 */
11 /* D-70794 Filderstadt */
12 /* EMail: uz@cc65.org */
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. */
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: */
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 */
32 /*****************************************************************************/
54 /*****************************************************************************/
56 /*****************************************************************************/
61 static const char* SymTab[0x10000];
65 /*****************************************************************************/
67 /*****************************************************************************/
71 static const char* MakeLabelName (unsigned Addr)
72 /* Make the default label name from the given address and return it in a
76 static char LabelBuf [32];
77 xsprintf (LabelBuf, sizeof (LabelBuf), "L%04X", Addr);
83 static void AddLabel (unsigned Addr, attr_t Attr, const char* Name)
86 /* Get an existing label attribute */
87 attr_t ExistingAttr = GetLabelAttr (Addr);
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?).
94 if (ExistingAttr == Attr &&
95 ((Name == 0 && SymTab[Addr] == 0) || strcmp (SymTab[Addr], Name) == 0)) {
98 Error ("Duplicate label for address $%04X: %s/%s", Addr, SymTab[Addr], Name);
101 /* Create a new label (xstrdup will return NULL if input NULL) */
102 SymTab[Addr] = xstrdup (Name);
104 /* Remember the attribute */
105 MarkAddr (Addr, Attr);
110 void AddIntLabel (unsigned Addr)
111 /* Add an internal label using the address to generate the name. */
113 AddLabel (Addr, atIntLabel, MakeLabelName (Addr));
118 void AddExtLabel (unsigned Addr, const char* Name)
119 /* Add an external label */
121 AddLabel (Addr, atExtLabel, Name);
126 void AddUnnamedLabel (unsigned Addr)
127 /* Add an unnamed label */
129 AddLabel (Addr, atUnnamedLabel, 0);
134 void AddDepLabel (unsigned Addr, attr_t Attr, const char* BaseName, unsigned Offs)
135 /* Add a dependent label at the given address using "basename+Offs" as the new
139 /* Allocate memory for the dependent label name */
140 unsigned NameLen = strlen (BaseName);
141 char* DepName = xmalloc (NameLen + 7); /* "+$ABCD\0" */
143 /* Create the new name in the buffer */
145 sprintf (DepName, "%s+$%02X", BaseName, Offs);
147 sprintf (DepName, "%s+%u", BaseName, Offs);
150 /* Define the labels */
151 AddLabel (Addr, Attr | atDepLabel, DepName);
153 /* Free the name buffer */
159 static void AddLabelRange (unsigned Addr, attr_t Attr,
160 const char* Name, unsigned Count)
161 /* Add a label for a range. The first entry gets the label "Name" while the
162 * others get "Name+offs".
165 /* Define the label */
166 AddLabel (Addr, Attr, Name);
168 /* Define dependent labels if necessary */
172 /* Setup the format string */
173 const char* Format = UseHexOffs? "$%02X" : "%u";
175 /* Allocate memory for the dependent label names */
176 unsigned NameLen = strlen (Name);
177 char* DepName = xmalloc (NameLen + 7); /* "+$ABCD" */
178 char* DepOffs = DepName + NameLen + 1;
180 /* Copy the original name into the buffer */
181 memcpy (DepName, Name, NameLen);
182 DepName[NameLen] = '+';
184 /* Define the labels */
185 for (Offs = 1; Offs < Count; ++Offs) {
186 sprintf (DepOffs, Format, Offs);
187 AddLabel (Addr + Offs, Attr | atDepLabel, DepName);
190 /* Free the name buffer */
197 void AddIntLabelRange (unsigned Addr, const char* Name, unsigned Count)
198 /* Add an internal label for a range. The first entry gets the label "Name"
199 * while the others get "Name+offs".
202 /* Define the label range */
203 AddLabelRange (Addr, atIntLabel, Name, Count);
208 void AddExtLabelRange (unsigned Addr, const char* Name, unsigned Count)
209 /* Add an external label for a range. The first entry gets the label "Name"
210 * while the others get "Name+offs".
213 /* Define the label range */
214 AddLabelRange (Addr, atExtLabel, Name, Count);
219 int HaveLabel (unsigned Addr)
220 /* Check if there is a label for the given address */
222 /* Check for a label */
223 return (GetLabelAttr (Addr) != atNoLabel);
228 int MustDefLabel (unsigned Addr)
229 /* Return true if we must define a label for this address, that is, if there
230 * is a label at this address, and it is an external or internal label.
233 /* Get the label attribute */
234 attr_t A = GetLabelAttr (Addr);
236 /* Check for an internal, external, or unnamed label */
237 return (A == atExtLabel || A == atIntLabel || A == atUnnamedLabel);
242 const char* GetLabelName (unsigned Addr)
243 /* Return the label name for an address */
245 /* Get the label attribute */
246 attr_t A = GetLabelAttr (Addr);
248 /* Special case unnamed labels, because these don't have a named stored in
249 * the symbol table to save space.
251 if (A == atUnnamedLabel) {
254 /* Return the label if any */
261 const char* GetLabel (unsigned Addr, unsigned RefFrom)
262 /* Return the label name for an address, as it is used in a label reference.
263 * RefFrom is the address the label is referenced from. This is needed in case
264 * of unnamed labels, to determine the name.
267 static const char* FwdLabels[] = {
268 ":+", ":++", ":+++", ":++++", ":+++++", ":++++++", ":+++++++",
269 ":++++++++", ":+++++++++", ":++++++++++"
271 static const char* BackLabels[] = {
272 ":-", ":--", ":---", ":----", ":-----", ":------", ":-------",
273 ":--------", ":---------", ":----------"
276 /* Get the label attribute */
277 attr_t A = GetLabelAttr (Addr);
279 /* Special case unnamed labels, because these don't have a named stored in
280 * the symbol table to save space.
282 if (A == atUnnamedLabel) {
286 /* Search forward or backward depending in which direction the label
289 if (Addr <= RefFrom) {
290 /* Search backwards */
291 unsigned I = RefFrom;
294 A = GetLabelAttr (I);
295 if (A == atUnnamedLabel) {
297 if (Count >= sizeof (BackLabels) / sizeof (BackLabels[0])) {
298 Error ("Too many unnamed labels between label at "
299 "$%04X and reference at $%04X", Addr, RefFrom);
304 /* Return the label name */
305 return BackLabels[Count-1];
308 /* Search forwards */
309 unsigned I = RefFrom;
312 A = GetLabelAttr (I);
313 if (A == atUnnamedLabel) {
315 if (Count >= sizeof (FwdLabels) / sizeof (FwdLabels[0])) {
316 Error ("Too many unnamed labels between label at "
317 "$%04X and reference at $%04X", Addr, RefFrom);
322 /* Return the label name */
323 return FwdLabels[Count-1];
327 /* Return the label if any */
334 void ForwardLabel (unsigned Offs)
335 /* If necessary, output a forward label, one that is within the next few
336 * bytes and is therefore output as "label = * + x".
339 /* Calculate the actual address */
340 unsigned long Addr = PC + Offs;
342 /* Get the type of the label */
343 attr_t A = GetLabelAttr (Addr);
345 /* If there is no label, or just a dependent one, bail out */
346 if (A == atNoLabel || (A & atDepLabel) != 0) {
350 /* An unnamed label cannot be output as a forward declaration, so this is
353 if (A == atUnnamedLabel) {
354 Error ("Cannot define unnamed label at address $%04lX", Addr);
357 /* Output the label */
358 DefForward (GetLabelName (Addr), GetComment (Addr), Offs);
363 static void DefOutOfRangeLabel (unsigned long Addr)
364 /* Define one label that is outside code range. */
366 switch (GetLabelAttr (Addr)) {
370 DefConst (SymTab[Addr], GetComment (Addr), Addr);
374 Error ("Cannot define unnamed label at address $%04lX", Addr);
385 void DefOutOfRangeLabels (void)
386 /* Output any labels that are out of the loaded code range */
394 while (Addr < CodeStart) {
395 DefOutOfRangeLabel (Addr++);
398 /* Skip areas in code range */
399 while (Addr <= CodeEnd) {
400 if (GetStyleAttr (Addr) == atSkip) {
401 DefOutOfRangeLabel (Addr);
407 while (Addr < 0x10000) {
408 DefOutOfRangeLabel (Addr++);