]> git.sur5r.net Git - cc65/blob - src/ca65/lineinfo.c
Fix wrong line info sometimes output for macros: When macro parameters were
[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     /* Add the line info to the list of all line infos */
98     CollAppend (&LineInfoColl, LI);
99
100     /* Return the new struct */
101     return LI;
102 }
103
104
105
106 /*****************************************************************************/
107 /*                                   Code                                    */
108 /*****************************************************************************/
109
110
111
112 void InitLineInfo (void)
113 /* Initialize the line infos */
114 {
115     static const FilePos DefaultPos = STATIC_FILEPOS_INITIALIZER;
116
117     /* Increase the initial count of the line info collection */
118     CollGrow (&LineInfoColl, 200);
119
120     /* Allocate 8 slots */
121     AllocatedSlots = 8;
122     CurLineInfo = xmalloc (AllocatedSlots * sizeof (LineInfoSlot));
123
124     /* Initalize the predefined slots. Be sure to ccreate a new LineInfo for
125      * the default source. This is necessary to allow error message to be
126      * generated without any input file open.
127      */
128     UsedSlots = 2;
129     CurLineInfo[LI_SLOT_ASM].Type = LI_TYPE_ASM;        /* Count = 0 */
130     CurLineInfo[LI_SLOT_ASM].Info = NewLineInfo (LI_TYPE_ASM, &DefaultPos);
131     CurLineInfo[LI_SLOT_EXT].Type = LI_TYPE_EXT;        /* Count = 0 */
132     CurLineInfo[LI_SLOT_EXT].Info = 0;
133 }
134
135
136
137 int AllocLineInfoSlot (unsigned Type, unsigned Count)
138 /* Allocate a line info slot of the given type and return the slot index */
139 {
140     /* Grow the array if necessary */
141     if (UsedSlots >= AllocatedSlots) {
142         LineInfoSlot* NewLineInfo;
143         AllocatedSlots *= 2;
144         NewLineInfo = xmalloc (AllocatedSlots * sizeof (LineInfoSlot));
145         memcpy (NewLineInfo, CurLineInfo, UsedSlots * sizeof (LineInfoSlot));
146         xfree (CurLineInfo);
147         CurLineInfo = NewLineInfo;
148     }
149
150     /* Array is now big enough, add the new data */
151     CurLineInfo[UsedSlots].Type = LI_MAKE_TYPE(Type, Count);
152     CurLineInfo[UsedSlots].Info = 0;
153
154     /* Increment the count and return the index of the new slot */
155     return (int) UsedSlots++;
156 }
157
158
159
160 void FreeLineInfoSlot (int Slot)
161 /* Free the line info in the given slot. Note: Alloc/Free must be used in
162  * FIFO order.
163  */
164 {
165     /* Check the parameter */
166     PRECONDITION (Slot == (int) UsedSlots - 1);
167
168     /* Free the last entry */
169     CurLineInfo[Slot].Info = 0;
170     --UsedSlots;
171 }
172
173
174
175 void GenLineInfo (int Slot, const FilePos* Pos)
176 /* Generate a new line info in the given slot */
177 {
178     /* Get a pointer to the slot */
179     LineInfoSlot* S = CurLineInfo + Slot;
180
181     /* Generate new data only if it is different from the existing. */
182     if (S->Info && CompareFilePos (&S->Info->Pos, Pos) == 0) {
183         /* Already there */
184         return;
185     }
186
187     /* Allocate new data */
188     S->Info = NewLineInfo (S->Type, Pos);
189 }
190
191
192
193 void ClearLineInfo (int Slot)
194 /* Clear the line info in the given slot */
195 {
196     /* Zero the pointer */
197     CurLineInfo[Slot].Info = 0;
198 }
199
200
201
202 void GetFullLineInfo (Collection* LineInfos, unsigned IncUsage)
203 /* Return full line infos, that is line infos for all slots in LineInfos. The
204  * function will clear LineInfos before usage and will increment the usage
205  * counter by IncUsage for all line infos returned.
206  */
207 {
208     unsigned I;
209
210     /* Clear the collection */
211     CollDeleteAll (LineInfos);
212
213     /* Copy all valid line infos to the collection */
214     for (I = 0; I < UsedSlots; ++I) {
215
216         /* Get the line info from the slot */
217         LineInfo* LI = CurLineInfo[I].Info;
218
219         /* Ignore empty slots */
220         if (LI) {
221             LI->Usage += IncUsage;
222             CollAppend (LineInfos, LI);
223         }
224     }
225 }
226
227
228
229 LineInfo* UseLineInfo (LineInfo* LI)
230 /* Increase the reference count of the given line info and return it. The
231  * function will gracefully accept NULL pointers and do nothing in this case.
232  */
233 {
234     if (LI) {
235         ++LI->Usage;
236     }
237     return LI;
238 }
239
240
241
242 LineInfo* ReleaseLineInfo (LineInfo* LI)
243 /* Decrease the reference count of the given line info and return it. The
244  * function will gracefully accept NULL pointers and do nothing in this case.
245  */
246 {
247     if (LI) {
248         /* Cannot decrease below zero */
249         CHECK (LI->Usage != 0);
250         --LI->Usage;
251     }
252     return LI;
253 }
254
255
256
257 static int CmpLineInfo (void* Data attribute ((unused)),
258                         const void* LI1_, const void* LI2_)
259 /* Compare function for the sort */
260 {
261     /* Cast the pointers */
262     const LineInfo* LI1 = LI1_;
263     const LineInfo* LI2 = LI2_;
264
265     /* Unreferenced line infos are always larger, otherwise sort by file,
266      * then by line, then by column.
267      */
268     if ((LI1->Usage == 0) == (LI2->Usage == 0)) {
269         /* Both are either referenced or unreferenced */
270         return CompareFilePos (&LI1->Pos, &LI2->Pos);
271     } else {
272         if (LI1->Usage > 0) {
273             return -1;
274         } else {
275             return 1;
276         }
277     }
278 }
279
280
281
282 void WriteLineInfo (const Collection* LineInfos)
283 /* Write a list of line infos to the object file. MakeLineInfoIndex has to
284  * be called before!
285  */
286 {
287     unsigned I;
288
289     /* Write the count */
290     ObjWriteVar (CollCount (LineInfos));
291
292     /* Write the line info indices */
293     for (I = 0; I < CollCount (LineInfos); ++I) {
294
295         /* Get a pointer to the line info */
296         const LineInfo* LI = CollConstAt (LineInfos, I);
297
298         /* Check the index */
299         CHECK (LI->Index != INV_LINEINFO_INDEX);
300
301         /* Write the index to the file */
302         ObjWriteVar (LI->Index);
303     }
304 }
305
306
307
308 void MakeLineInfoIndex (void)
309 /* Index the line infos */
310 {
311     unsigned I;
312
313     /* Sort the line info list */
314     CollSort (&LineInfoColl, CmpLineInfo, 0);
315
316     /* Walk over the list, index the line infos and count the used ones */
317     UsedLineInfoCount = 0;
318     for (I = 0; I < CollCount (&LineInfoColl); ++I) {
319         /* Get a pointer to this line info */
320         LineInfo* LI = CollAtUnchecked (&LineInfoColl, I);
321
322         /* If it is invalid, terminate the loop. All unused line infos were
323          * placed at the end of the collection by the sort.
324          */
325         if (LI->Usage == 0) {
326             break;
327         }
328
329         /* Index and count this one */
330         LI->Index = I;
331         ++UsedLineInfoCount;
332     }
333 }
334
335
336
337 void WriteLineInfos (void)
338 /* Write a list of all line infos to the object file. */
339 {
340     unsigned I;
341
342     /* Tell the object file module that we're about to write line infos */
343     ObjStartLineInfos ();
344
345     /* Write the line info count to the list */
346     ObjWriteVar (UsedLineInfoCount);
347
348     /* Walk over the list and write all line infos */
349     for (I = 0; I < UsedLineInfoCount; ++I) {
350         /* Get a pointer to this line info */
351         LineInfo* LI = CollAt (&LineInfoColl, I);
352
353         /* Write the type and count of the line info */
354         ObjWriteVar (LI->Type);
355
356         /* Write the source file position */
357         ObjWritePos (&LI->Pos);
358     }
359
360     /* End of line infos */
361     ObjEndLineInfos ();
362 }
363
364
365