1 /*****************************************************************************/
5 /* Source file line info structure */
9 /* (C) 2001-2011, Ullrich von Bassewitz */
10 /* Roemerstrasse 52 */
11 /* 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 /*****************************************************************************/
60 static unsigned HT_GenHash (const void* Key);
61 /* Generate the hash over a key. */
63 static const void* HT_GetKey (const void* Entry);
64 /* Given a pointer to the user entry data, return a pointer to the key */
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.
74 /*****************************************************************************/
76 /*****************************************************************************/
80 /* Structure that holds the key for a line info */
81 typedef struct LineInfoKey LineInfoKey;
83 FilePos Pos; /* File position */
84 unsigned Type; /* Type/count of line info */
87 /* Structure that holds line info */
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 */
99 /* Collection containing all line infos */
100 static Collection LineInfoList = STATIC_COLLECTION_INITIALIZER;
102 /* Collection with currently active line infos */
103 static Collection CurLineInfo = STATIC_COLLECTION_INITIALIZER;
105 /* Hash table functions */
106 static const HashFunctions HashFunc = {
112 /* Line info hash table */
113 static HashTable LineInfoTab = STATIC_HASHTABLE_INITIALIZER (1051, &HashFunc);
115 /* The current assembler input line */
116 static LineInfo* AsmLineInfo = 0;
120 /*****************************************************************************/
121 /* Hash table functions */
122 /*****************************************************************************/
126 static unsigned HT_GenHash (const void* Key)
127 /* Generate the hash over a key. */
129 /* Key is a LineInfoKey pointer */
130 const LineInfoKey* K = Key;
132 /* Hash over a combination of type, file and line */
133 return HashInt ((K->Type << 21) ^ (K->Pos.Name << 14) ^ K->Pos.Line);
138 static const void* HT_GetKey (const void* Entry)
139 /* Given a pointer to the user entry data, return a pointer to the key */
141 return &((const LineInfo*)Entry)->Key;
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.
152 /* Convert both parameters to FileInfoKey pointers */
153 const LineInfoKey* K1 = Key1;
154 const LineInfoKey* K2 = Key2;
156 /* Compare line number, then file and type */
157 int Res = (int)K2->Pos.Line - (int)K1->Pos.Line;
159 Res = (int)K2->Pos.Name - (int)K1->Pos.Name;
161 Res = (int)K2->Type - (int)K1->Type;
171 /*****************************************************************************/
172 /* struct LineInfo */
173 /*****************************************************************************/
177 static LineInfo* NewLineInfo (const LineInfoKey* Key)
178 /* Create and return a new line info. Usage will be zero. */
180 /* Allocate memory */
181 LineInfo* LI = xmalloc (sizeof (LineInfo));
183 /* Initialize the fields */
184 InitHashNode (&LI->Node);
188 InitCollection (&LI->Spans);
189 InitCollection (&LI->OpenSpans);
191 /* Add it to the hash table, so we will find it if necessary */
192 HT_Insert (&LineInfoTab, LI);
194 /* Return the new struct */
200 static void FreeLineInfo (LineInfo* LI)
201 /* Free a LineInfo structure */
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);
208 /* Free the structure itself */
214 static int CheckLineInfo (void* Entry, void* Data attribute ((unused)))
215 /* Called from HT_Walk. Remembers used line infos and assigns them an id */
217 /* Entry is actually a line info */
218 LineInfo* LI = Entry;
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 */
227 return 1; /* Remove entry from table */
233 /*****************************************************************************/
235 /*****************************************************************************/
240 static void DumpLineInfos (const char* Title, const Collection* C)
241 /* Dump line infos from the given collection */
244 fprintf (stderr, "%s:\n", Title);
245 for (I = 0; I < CollCount (C); ++I) {
246 const LineInfo* LI = CollConstAt (C, I);
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;
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);
266 void InitLineInfo (void)
267 /* Initialize the line infos */
269 static const FilePos DefaultPos = STATIC_FILEPOS_INITIALIZER;
271 /* Increase the initial count of the line info collection */
272 CollGrow (&LineInfoList, 200);
274 /* Create a LineInfo for the default source. This is necessary to allow
275 * error message to be generated without any input file open.
277 AsmLineInfo = StartLine (&DefaultPos, LI_TYPE_ASM, 0);
282 void DoneLineInfo (void)
283 /* Close down line infos */
285 /* Close all current line infos */
286 unsigned Count = CollCount (&CurLineInfo);
288 EndLine (CollAt (&CurLineInfo, --Count));
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
295 HT_Walk (&LineInfoTab, CheckLineInfo, 0);
300 void EndLine (LineInfo* LI)
301 /* End a line that is tracked by the given LineInfo structure */
303 /* Close the spans for the line */
304 CloseSpanList (&LI->OpenSpans);
306 /* Move the spans to the list of all spans for this line, then clear the
307 * list of open spans.
309 CollTransfer (&LI->Spans, &LI->OpenSpans);
310 CollDeleteAll (&LI->OpenSpans);
312 /* Line info is no longer active - remove it from the list of current
315 CollDeleteItem (&CurLineInfo, LI);
320 LineInfo* StartLine (const FilePos* Pos, unsigned Type, unsigned Count)
321 /* Start line info for a new line */
326 /* Prepare the key struct */
328 Key.Type = LI_MAKE_TYPE (Type, Count);
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.
333 LI = HT_Find (&LineInfoTab, &Key);
335 /* Allocate a new LineInfo */
336 LI = NewLineInfo (&Key);
339 /* Open the spans for this line info */
340 OpenSpanList (&LI->OpenSpans);
342 /* Add the line info to the list of current line infos */
343 CollAppend (&CurLineInfo, LI);
345 /* Return the new info */
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.
357 /* Check if we can reuse the old line */
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 */
365 /* Line has changed -> end the old line */
366 EndLine (AsmLineInfo);
369 /* Start a new line using the current line info */
370 AsmLineInfo = StartLine (&CurTok.Pos, LI_TYPE_ASM, 0);
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.
380 ++AsmLineInfo->RefCount;
386 void ReleaseLineInfo (LineInfo* LI)
387 /* Decrease the reference count for a line info */
389 /* Decrease the reference counter */
390 CHECK (LI->RefCount > 0);
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.
404 /* Bum the reference counter for all active line infos */
405 for (I = 0; I < CollCount (&CurLineInfo); ++I) {
406 ++((LineInfo*)CollAt (&CurLineInfo, I))->RefCount;
409 /* Copy all line infos over */
410 CollTransfer (LineInfos, &CurLineInfo);
415 void ReleaseFullLineInfo (Collection* LineInfos)
416 /* Decrease the reference count for a collection full of LineInfos, then clear
422 /* Walk over all entries */
423 for (I = 0; I < CollCount (LineInfos); ++I) {
424 /* Release the the line info */
425 ReleaseLineInfo (CollAt (LineInfos, I));
428 /* Delete all entries */
429 CollDeleteAll (LineInfos);
434 const FilePos* GetSourcePos (const LineInfo* LI)
435 /* Return the source file position from the given line info */
442 unsigned GetLineInfoType (const LineInfo* LI)
443 /* Return the type of a line info */
445 return LI_GET_TYPE (LI->Key.Type);
450 void WriteLineInfo (const Collection* LineInfos)
451 /* Write a list of line infos to the object file. */
455 /* Write the count */
456 ObjWriteVar (CollCount (LineInfos));
458 /* Write the line info indices */
459 for (I = 0; I < CollCount (LineInfos); ++I) {
461 /* Get a pointer to the line info */
462 const LineInfo* LI = CollConstAt (LineInfos, I);
465 CHECK (LI->Id != ~0U);
467 /* Write the index to the file */
468 ObjWriteVar (LI->Id);
474 void WriteLineInfos (void)
475 /* Write a list of all line infos to the object file. */
479 /* Tell the object file module that we're about to write line infos */
480 ObjStartLineInfos ();
482 /* Write the line info count to the list */
483 ObjWriteVar (CollCount (&LineInfoList));
485 /* Walk over the list and write all line infos */
486 for (I = 0; I < CollCount (&LineInfoList); ++I) {
488 /* Get a pointer to this line info */
489 LineInfo* LI = CollAt (&LineInfoList, I);
491 /* Write the source file position */
492 ObjWritePos (&LI->Key.Pos);
494 /* Write the type and count of the line info */
495 ObjWriteVar (LI->Key.Type);
497 /* Write the ids of the spans for this line */
498 WriteSpanList (&LI->Spans);
501 /* End of line infos */