]> git.sur5r.net Git - cc65/blob - src/ca65/lineinfo.c
Removed (pretty inconsistently used) tab chars from source code base.
[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 <stdio.h>
37 #include <string.h>
38
39 /* common */
40 #include "coll.h"
41 #include "hashfunc.h"
42 #include "xmalloc.h"
43
44 /* ca65 */
45 #include "filetab.h"
46 #include "global.h"
47 #include "lineinfo.h"
48 #include "objfile.h"
49 #include "scanner.h"
50 #include "span.h"
51
52
53
54 /*****************************************************************************/
55 /*                                 Forwards                                  */
56 /*****************************************************************************/
57
58
59
60 static unsigned HT_GenHash (const void* Key);
61 /* Generate the hash over a key. */
62
63 static const void* HT_GetKey (const void* Entry);
64 /* Given a pointer to the user entry data, return a pointer to the key */
65
66 static int HT_Compare (const void* Key1, const void* Key2);
67 /* Compare two keys. The function must return a value less than zero if
68  * Key1 is smaller than Key2, zero if both are equal, and a value greater
69  * than zero if Key1 is greater then Key2.
70  */
71
72
73
74 /*****************************************************************************/
75 /*                                   Data                                    */
76 /*****************************************************************************/
77
78
79
80 /* Structure that holds the key for a line info */
81 typedef struct LineInfoKey LineInfoKey;
82 struct LineInfoKey {
83     FilePos         Pos;                /* File position */
84     unsigned        Type;               /* Type/count of line info */
85 };
86
87 /* Structure that holds line info */
88 struct LineInfo {
89     HashNode        Node;               /* Hash table node */
90     unsigned        Id;                 /* Index */
91     LineInfoKey     Key;                /* Key for this line info */
92     unsigned        RefCount;           /* Reference counter */
93     Collection      Spans;              /* Segment spans for this line info */
94     Collection      OpenSpans;          /* List of currently open spans */
95 };
96
97
98
99 /* Collection containing all line infos */
100 static Collection LineInfoList = STATIC_COLLECTION_INITIALIZER;
101
102 /* Collection with currently active line infos */
103 static Collection CurLineInfo = STATIC_COLLECTION_INITIALIZER;
104
105 /* Hash table functions */
106 static const HashFunctions HashFunc = {
107     HT_GenHash,
108     HT_GetKey,
109     HT_Compare
110 };
111
112 /* Line info hash table */
113 static HashTable LineInfoTab = STATIC_HASHTABLE_INITIALIZER (1051, &HashFunc);
114
115 /* The current assembler input line */
116 static LineInfo* AsmLineInfo = 0;
117
118
119
120 /*****************************************************************************/
121 /*                           Hash table functions                            */
122 /*****************************************************************************/
123
124
125
126 static unsigned HT_GenHash (const void* Key)
127 /* Generate the hash over a key. */
128 {
129     /* Key is a LineInfoKey pointer */
130     const LineInfoKey* K = Key;
131
132     /* Hash over a combination of type, file and line */
133     return HashInt ((K->Type << 21) ^ (K->Pos.Name << 14) ^ K->Pos.Line);
134 }
135
136
137
138 static const void* HT_GetKey (const void* Entry)
139 /* Given a pointer to the user entry data, return a pointer to the key */
140 {
141     return &((const LineInfo*)Entry)->Key;
142 }
143
144
145
146 static int HT_Compare (const void* Key1, const void* Key2)
147 /* Compare two keys. The function must return a value less than zero if
148  * Key1 is smaller than Key2, zero if both are equal, and a value greater
149  * than zero if Key1 is greater then Key2.
150  */
151 {
152     /* Convert both parameters to FileInfoKey pointers */
153     const LineInfoKey* K1 = Key1;
154     const LineInfoKey* K2 = Key2;
155
156     /* Compare line number, then file and type */
157     int Res = (int)K2->Pos.Line - (int)K1->Pos.Line;
158     if (Res == 0) {
159         Res = (int)K2->Pos.Name - (int)K1->Pos.Name;
160         if (Res == 0) {
161             Res = (int)K2->Type - (int)K1->Type;
162         }
163     }
164
165     /* Done */
166     return Res;
167 }
168
169
170
171 /*****************************************************************************/
172 /*                              struct LineInfo                              */
173 /*****************************************************************************/
174
175
176
177 static LineInfo* NewLineInfo (const LineInfoKey* Key)
178 /* Create and return a new line info. Usage will be zero. */
179 {
180     /* Allocate memory */
181     LineInfo* LI = xmalloc (sizeof (LineInfo));
182
183     /* Initialize the fields */
184     InitHashNode (&LI->Node);
185     LI->Id        = ~0U;
186     LI->Key       = *Key;
187     LI->RefCount  = 0;
188     InitCollection (&LI->Spans);
189     InitCollection (&LI->OpenSpans);
190
191     /* Add it to the hash table, so we will find it if necessary */
192     HT_Insert (&LineInfoTab, LI);
193
194     /* Return the new struct */
195     return LI;
196 }
197
198
199
200 static void FreeLineInfo (LineInfo* LI)
201 /* Free a LineInfo structure */
202 {
203     /* Free the Spans collection. It is supposed to be empty */
204     CHECK (CollCount (&LI->Spans) == 0);
205     DoneCollection (&LI->Spans);
206     DoneCollection (&LI->OpenSpans);
207
208     /* Free the structure itself */
209     xfree (LI);
210 }
211
212
213
214 static int CheckLineInfo (void* Entry, void* Data attribute ((unused)))
215 /* Called from HT_Walk. Remembers used line infos and assigns them an id */
216 {
217     /* Entry is actually a line info */
218     LineInfo* LI = Entry;
219
220     /* The entry is used if there are spans or the ref counter is non zero */
221     if (LI->RefCount > 0 || CollCount (&LI->Spans) > 0) {
222         LI->Id = CollCount (&LineInfoList);
223         CollAppend (&LineInfoList, LI);
224         return 0;       /* Keep the entry */
225     } else {
226         FreeLineInfo (LI);
227         return 1;       /* Remove entry from table */
228     }
229 }
230
231
232
233 /*****************************************************************************/
234 /*                                   Code                                    */
235 /*****************************************************************************/
236
237
238
239 #if 0
240 static void DumpLineInfos (const char* Title, const Collection* C)
241 /* Dump line infos from the given collection */
242 {
243     unsigned I;
244     fprintf (stderr, "%s:\n", Title);
245     for (I = 0; I < CollCount (C); ++I) {
246         const LineInfo* LI = CollConstAt (C, I);
247         const char* Type;
248         switch (GetLineInfoType (LI)) {
249             case LI_TYPE_ASM:           Type = "ASM";           break;
250             case LI_TYPE_EXT:           Type = "EXT";           break;
251             case LI_TYPE_MACRO:         Type = "MACRO";         break;
252             case LI_TYPE_MACPARAM:      Type = "MACPARAM";      break;
253             default:                    Type = "unknown";       break;
254         }
255         fprintf (stderr,
256                  "%2u: %-8s %2u %-16s %u/%u\n",
257                  I, Type, LI->Key.Pos.Name,
258                  SB_GetConstBuf (GetFileName (LI->Key.Pos.Name)),
259                  LI->Key.Pos.Line, LI->Key.Pos.Col);
260     }
261 }
262 #endif
263
264
265
266 void InitLineInfo (void)
267 /* Initialize the line infos */
268 {
269     static const FilePos DefaultPos = STATIC_FILEPOS_INITIALIZER;
270
271     /* Increase the initial count of the line info collection */
272     CollGrow (&LineInfoList, 200);
273
274     /* Create a LineInfo for the default source. This is necessary to allow
275      * error message to be generated without any input file open.
276      */
277     AsmLineInfo = StartLine (&DefaultPos, LI_TYPE_ASM, 0);
278 }
279
280
281
282 void DoneLineInfo (void)
283 /* Close down line infos */
284 {
285     /* Close all current line infos */
286     unsigned Count = CollCount (&CurLineInfo);
287     while (Count) {
288         EndLine (CollAt (&CurLineInfo, --Count));
289     }
290
291     /* Walk over the entries in the hash table and sort them into used and
292      * unused ones. Add the used ones to the line info list and assign them
293      * an id.
294      */
295     HT_Walk (&LineInfoTab, CheckLineInfo, 0);
296 }
297
298
299
300 void EndLine (LineInfo* LI)
301 /* End a line that is tracked by the given LineInfo structure */
302 {
303     /* Close the spans for the line */
304     CloseSpanList (&LI->OpenSpans);
305
306     /* Move the spans to the list of all spans for this line, then clear the
307      * list of open spans.
308      */
309     CollTransfer (&LI->Spans, &LI->OpenSpans);
310     CollDeleteAll (&LI->OpenSpans);
311
312     /* Line info is no longer active - remove it from the list of current
313      * line infos.
314      */
315     CollDeleteItem (&CurLineInfo, LI);
316 }
317
318
319
320 LineInfo* StartLine (const FilePos* Pos, unsigned Type, unsigned Count)
321 /* Start line info for a new line */
322 {
323     LineInfoKey Key;
324     LineInfo* LI;
325
326     /* Prepare the key struct */
327     Key.Pos   = *Pos;
328     Key.Type  = LI_MAKE_TYPE (Type, Count);
329
330     /* Try to find a line info with this position and type in the hash table.
331      * If so, reuse it. Otherwise create a new one.
332      */
333     LI = HT_Find (&LineInfoTab, &Key);
334     if (LI == 0) {
335         /* Allocate a new LineInfo */
336         LI = NewLineInfo (&Key);
337     }
338
339     /* Open the spans for this line info */
340     OpenSpanList (&LI->OpenSpans);
341
342     /* Add the line info to the list of current line infos */
343     CollAppend (&CurLineInfo, LI);
344
345     /* Return the new info */
346     return LI;
347 }
348
349
350
351 void NewAsmLine (void)
352 /* Start a new assembler input line. Use this function when generating new
353  * line of LI_TYPE_ASM. It will check if line and/or file have actually
354  * changed, end the old and start the new line as necessary.
355  */
356 {
357     /* Check if we can reuse the old line */
358     if (AsmLineInfo) {
359         if (AsmLineInfo->Key.Pos.Line == CurTok.Pos.Line &&
360             AsmLineInfo->Key.Pos.Name == CurTok.Pos.Name) {
361             /* We do already have line info for this line */
362             return;
363         }
364
365         /* Line has changed -> end the old line */
366         EndLine (AsmLineInfo);
367     }
368
369     /* Start a new line using the current line info */
370     AsmLineInfo = StartLine (&CurTok.Pos, LI_TYPE_ASM, 0);
371 }
372
373
374
375 LineInfo* GetAsmLineInfo (void)
376 /* Return the line info for the current assembler file. The function will
377  * bump the reference counter before returning the line info.
378  */
379 {
380     ++AsmLineInfo->RefCount;
381     return AsmLineInfo;
382 }
383
384
385
386 void ReleaseLineInfo (LineInfo* LI)
387 /* Decrease the reference count for a line info */
388 {
389     /* Decrease the reference counter */
390     CHECK (LI->RefCount > 0);
391     ++LI->RefCount;
392 }
393
394
395
396 void GetFullLineInfo (Collection* LineInfos)
397 /* Return full line infos, that is line infos for currently active Slots. The
398  * infos will be added to the given collection, existing entries will be left
399  * intact. The reference count of all added entries will be increased.
400  */
401 {
402     unsigned I;
403
404     /* Bum the reference counter for all active line infos */
405     for (I = 0; I < CollCount (&CurLineInfo); ++I) {
406         ++((LineInfo*)CollAt (&CurLineInfo, I))->RefCount;
407     }
408
409     /* Copy all line infos over */
410     CollTransfer (LineInfos, &CurLineInfo);
411 }
412
413
414
415 void ReleaseFullLineInfo (Collection* LineInfos)
416 /* Decrease the reference count for a collection full of LineInfos, then clear
417  * the collection.
418  */
419 {
420     unsigned I;
421
422     /* Walk over all entries */
423     for (I = 0; I < CollCount (LineInfos); ++I) {
424         /* Release the the line info */
425         ReleaseLineInfo (CollAt (LineInfos, I));
426     }
427
428     /* Delete all entries */
429     CollDeleteAll (LineInfos);
430 }
431
432
433
434 const FilePos* GetSourcePos (const LineInfo* LI)
435 /* Return the source file position from the given line info */
436 {
437     return &LI->Key.Pos;
438 }
439
440
441
442 unsigned GetLineInfoType (const LineInfo* LI)
443 /* Return the type of a line info */
444 {
445     return LI_GET_TYPE (LI->Key.Type);
446 }
447
448
449
450 void WriteLineInfo (const Collection* LineInfos)
451 /* Write a list of line infos to the object file. */
452 {
453     unsigned I;
454
455     /* Write the count */
456     ObjWriteVar (CollCount (LineInfos));
457
458     /* Write the line info indices */
459     for (I = 0; I < CollCount (LineInfos); ++I) {
460
461         /* Get a pointer to the line info */
462         const LineInfo* LI = CollConstAt (LineInfos, I);
463
464         /* Safety */
465         CHECK (LI->Id != ~0U);
466
467         /* Write the index to the file */
468         ObjWriteVar (LI->Id);
469     }
470 }
471
472
473
474 void WriteLineInfos (void)
475 /* Write a list of all line infos to the object file. */
476 {
477     unsigned I;
478
479     /* Tell the object file module that we're about to write line infos */
480     ObjStartLineInfos ();
481
482     /* Write the line info count to the list */
483     ObjWriteVar (CollCount (&LineInfoList));
484
485     /* Walk over the list and write all line infos */
486     for (I = 0; I < CollCount (&LineInfoList); ++I) {
487
488         /* Get a pointer to this line info */
489         LineInfo* LI = CollAt (&LineInfoList, I);
490
491         /* Write the source file position */
492         ObjWritePos (&LI->Key.Pos);
493
494         /* Write the type and count of the line info */
495         ObjWriteVar (LI->Key.Type);
496
497         /* Write the ids of the spans for this line */
498         WriteSpanList (&LI->Spans);
499     }
500
501     /* End of line infos */
502     ObjEndLineInfos ();
503 }
504
505
506