]> git.sur5r.net Git - cc65/blob - src/ca65/lineinfo.c
Actually generate basic line info.
[cc65] / src / ca65 / lineinfo.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                lineinfo.c                                 */
4 /*                                                                           */
5 /*                      Source file line info structure                      */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2001-2011, Ullrich von Bassewitz                                      */
10 /*                Roemerstrasse 52                                           */
11 /*                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 <string.h>
37 #include <limits.h>
38
39 /* common */
40 #include "coll.h"
41 #include "xmalloc.h"
42
43 /* ca65 */
44 #include "global.h"
45 #include "lineinfo.h"
46 #include "objfile.h"
47
48
49
50 /*****************************************************************************/
51 /*                                   Data                                    */
52 /*****************************************************************************/
53
54
55
56 /* An invalid line info index */
57 #define INV_LINEINFO_INDEX      UINT_MAX
58
59 /* Collection containing all line infos */
60 static Collection LineInfoColl = STATIC_COLLECTION_INITIALIZER;
61
62 /* Number of valid (=used) line infos in LineInfoColl */
63 static unsigned UsedLineInfoCount;
64
65 /* Entry in CurLineInfo */
66 typedef struct LineInfoSlot LineInfoSlot;
67 struct LineInfoSlot {
68     unsigned    Type;
69     LineInfo*   Info;
70 };
71
72 /* Dynamically allocated array of LineInfoSlots */
73 static LineInfoSlot* CurLineInfo;
74 static unsigned AllocatedSlots;
75 static unsigned UsedSlots;
76
77
78
79 /*****************************************************************************/
80 /*                              struct LineInfo                              */
81 /*****************************************************************************/
82
83
84
85 static LineInfo* NewLineInfo (unsigned Type, const FilePos* Pos)
86 /* Create and return a new line info. Usage will be zero. */
87 {
88     /* Allocate memory */
89     LineInfo* LI = xmalloc (sizeof (LineInfo));
90
91     /* Initialize the fields */
92     LI->Usage   = 0;
93     LI->Type    = Type;
94     LI->Index   = INV_LINEINFO_INDEX;
95     LI->Pos     = *Pos;
96
97     /* Return the new struct */
98     return LI;
99 }
100
101
102
103 static void FreeLineInfo (LineInfo* LI)
104 /* "Free" line info. If the usage counter is non zero, move it to the
105  * collection that contains all line infos, otherwise delete it.
106  * The function handles a NULL pointer transparently.
107  */
108 {
109     if (LI) {
110         if (LI->Usage > 0) {
111             CollAppend (&LineInfoColl, LI);
112         } else {
113             xfree (LI);
114         }
115     }
116 }
117
118
119
120 /*****************************************************************************/
121 /*                                   Code                                    */
122 /*****************************************************************************/
123
124
125
126 void InitLineInfo (void)
127 /* Initialize the line infos */
128 {
129     static const FilePos DefaultPos = STATIC_FILEPOS_INITIALIZER;
130
131     /* Allocate 8 slots */
132     AllocatedSlots = 8;
133     CurLineInfo = xmalloc (AllocatedSlots * sizeof (LineInfoSlot));
134
135     /* Initalize the predefined slots. Be sure to ccreate a new LineInfo for
136      * the default source. This is necessary to allow error message to be
137      * generated without any input file open.
138      */
139     UsedSlots = 2;
140     CurLineInfo[LI_SLOT_ASM].Type = LI_TYPE_ASM;
141     CurLineInfo[LI_SLOT_ASM].Info = NewLineInfo (LI_TYPE_ASM, &DefaultPos);
142     CurLineInfo[LI_SLOT_EXT].Type = LI_TYPE_EXT;
143     CurLineInfo[LI_SLOT_EXT].Info = 0;
144 }
145
146
147
148 unsigned AllocLineInfoSlot (unsigned Type)
149 /* Allocate a line info slot of the given type and return the slot index */
150 {
151     /* Grow the array if necessary */
152     if (UsedSlots >= AllocatedSlots) {
153         LineInfoSlot* NewLineInfo;
154         AllocatedSlots *= 2;
155         NewLineInfo = xmalloc (AllocatedSlots * sizeof (LineInfoSlot));
156         memcpy (NewLineInfo, CurLineInfo, UsedSlots * sizeof (LineInfoSlot));
157         xfree (CurLineInfo);
158         CurLineInfo = NewLineInfo;
159     }
160
161     /* Array is now big enough, add the new data */
162     CurLineInfo[UsedSlots].Type = Type;
163     CurLineInfo[UsedSlots].Info = 0;
164
165     /* Increment the count and return the index of the new slot */
166     return UsedSlots++;
167 }
168
169
170
171 void FreeLineInfoSlot (unsigned Slot)
172 /* Free the line info in the given slot. Note: Alloc/Free must be used in
173  * FIFO order.
174  */
175 {
176     /* Check the parameter */
177     PRECONDITION (Slot == UsedSlots - 1);
178
179     /* Free the last entry */
180     FreeLineInfo (CurLineInfo[Slot].Info);
181     --UsedSlots;
182 }
183
184
185
186 void GenLineInfo (unsigned Slot, const FilePos* Pos)
187 /* Generate a new line info in the given slot */
188 {
189     /* Get a pointer to the slot */
190     LineInfoSlot* S = CurLineInfo + Slot;
191
192     /* Check if we already have data */
193     if (S->Info) {
194         /* Generate new data only if it is different from the existing. */
195         if (CompareFilePos (&S->Info->Pos, Pos) == 0) {
196             /* Already there */
197             return;
198         }
199
200         /* We have data, but it's not identical. If it is in use, copy it to
201          * line info collection, otherwise delete it.
202          */
203         FreeLineInfo (S->Info);
204
205     }
206
207     /* Allocate new data */
208     S->Info = NewLineInfo (S->Type, Pos);
209 }
210
211
212
213 void ClearLineInfo (unsigned Slot)
214 /* Clear the line info in the given slot */
215 {
216     /* Get a pointer to the slot */
217     LineInfoSlot* S = CurLineInfo + Slot;
218
219     /* Free the struct and zero the pointer */
220     FreeLineInfo (S->Info);
221     S->Info = 0;
222 }
223
224
225
226 LineInfo* GetLineInfo (unsigned Slot)
227 /* Get the line info from the given slot */
228 {
229     PRECONDITION (Slot < UsedSlots);
230     return CurLineInfo[Slot].Info;
231 }
232
233
234
235 void GetFullLineInfo (Collection* LineInfos)
236 /* Return full line infos, that is line infos for all slots in LineInfos. The
237  * function does also increase the usage counter for all line infos returned.
238  */
239 {
240    unsigned I;
241
242     /* Copy all valid line infos to the collection */
243     for (I = 0; I < UsedSlots; ++I) {
244
245         /* Get the slot */
246         LineInfoSlot* S = CurLineInfo + I;
247
248         /* Ignore empty slots */
249         if (S->Info) {
250             ++S->Info->Usage;
251             CollAppend (LineInfos, S->Info);
252         }
253     }
254 }
255
256
257
258 LineInfo* UseLineInfo (LineInfo* LI)
259 /* Increase the reference count of the given line info and return it. The
260  * function will gracefully accept NULL pointers and do nothing in this case.
261  */
262 {
263     if (LI) {
264         ++LI->Usage;
265     }
266     return LI;
267 }
268
269
270
271 LineInfo* ReleaseLineInfo (LineInfo* LI)
272 /* Decrease the reference count of the given line info and return it. The
273  * function will gracefully accept NULL pointers and do nothing in this case.
274  */
275 {
276     if (LI) {
277         /* Cannot decrease below zero */
278         CHECK (LI->Usage != 0);
279         --LI->Usage;
280     }
281     return LI;
282 }
283
284
285
286 static int CmpLineInfo (void* Data attribute ((unused)),
287                         const void* LI1_, const void* LI2_)
288 /* Compare function for the sort */
289 {
290     /* Cast the pointers */
291     const LineInfo* LI1 = LI1_;
292     const LineInfo* LI2 = LI2_;
293
294     /* Unreferenced line infos are always larger, otherwise sort by file,
295      * then by line, then by column.
296      */
297     if ((LI1->Usage == 0) == (LI2->Usage == 0)) {
298         /* Both are either referenced or unreferenced */
299         return CompareFilePos (&LI1->Pos, &LI2->Pos);
300     } else {
301         if (LI1->Usage > 0) {
302             return -1;
303         } else {
304             return 1;
305         }
306     }
307 }
308
309
310
311 void WriteLineInfo (const Collection* LineInfos)
312 /* Write a list of line infos to the object file. MakeLineInfoIndex has to
313  * be called before!
314  */
315 {
316     unsigned I;
317
318     /* Write the count */
319     ObjWriteVar (CollCount (LineInfos));
320
321     /* Write the line info indices */
322     for (I = 0; I < CollCount (LineInfos); ++I) {
323
324         /* Get a pointer to the line info */
325         const LineInfo* LI = CollConstAt (LineInfos, I);
326
327         /* Check the index */
328         CHECK (LI->Index != INV_LINEINFO_INDEX);
329
330         /* Write the index to the file */
331         ObjWriteVar (LI->Index);
332     }
333 }
334
335
336
337 void MakeLineInfoIndex (void)
338 /* Index the line infos */
339 {
340     unsigned I;
341
342     /* Be sure to move pending line infos to the global list */
343     for (I = 0; I < UsedSlots; ++I) {
344         FreeLineInfo (CurLineInfo[I].Info);
345     }
346
347     /* Sort the collection */
348     CollSort (&LineInfoColl, CmpLineInfo, 0);
349
350     /* Walk over the list, index the line infos and count the used ones */
351     UsedLineInfoCount = 0;
352     for (I = 0; I < CollCount (&LineInfoColl); ++I) {
353         /* Get a pointer to this line info */
354         LineInfo* LI = CollAtUnchecked (&LineInfoColl, I);
355
356         /* If it is invalid, terminate the loop. All unused line infos were
357          * placed at the end of the collection by the sort.
358          */
359         if (LI->Usage == 0) {
360             break;
361         }
362
363         /* Index and count this one */
364         LI->Index = I;
365         ++UsedLineInfoCount;
366     }
367 }
368
369
370
371 void WriteLineInfos (void)
372 /* Write a list of all line infos to the object file. */
373 {
374     unsigned I;
375
376     /* Tell the object file module that we're about to write line infos */
377     ObjStartLineInfos ();
378
379     /* Write the line info count to the list */
380     ObjWriteVar (UsedLineInfoCount);
381
382     /* Walk over the list and write all line infos */
383     for (I = 0; I < UsedLineInfoCount; ++I) {
384         /* Get a pointer to this line info */
385         LineInfo* LI = CollAt (&LineInfoColl, I);
386         /* Write the source file position */
387         ObjWritePos (&LI->Pos);
388     }
389
390     /* End of line infos */
391     ObjEndLineInfos ();
392 }
393
394
395