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 | } |
415 | |