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 /*****************************************************************************/
52 /*****************************************************************************/
54 /*****************************************************************************/
58 static unsigned HT_GenHash (const void* Key);
59 /* Generate the hash over a key. */
61 static const void* HT_GetKey (const void* Entry);
62 /* Given a pointer to the user entry data, return a pointer to the key */
64 static int HT_Compare (const void* Key1, const void* Key2);
65 /* Compare two keys. The function must return a value less than zero if
66 * Key1 is smaller than Key2, zero if both are equal, and a value greater
67 * than zero if Key1 is greater then Key2.
72 /*****************************************************************************/
74 /*****************************************************************************/
78 /* Structure that holds the key for a line info */
79 typedef struct LineInfoKey LineInfoKey;
81 FilePos Pos; /* File position */
82 unsigned short Type; /* Type of line info */
83 unsigned short Count; /* Recursion counter */
86 /* Structure that holds line info */
88 HashNode Node; /* Hash table node */
89 unsigned Id; /* Index */
90 LineInfoKey Key; /* Key for this line info */
91 unsigned char Hashed; /* True if in hash list */
92 unsigned char Referenced; /* Force reference even if no spans */
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 << 18) ^ (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, then count */
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;
163 Res = (int)K2->Count - (int)K1->Count;
174 /*****************************************************************************/
175 /* struct LineInfo */
176 /*****************************************************************************/
180 static LineInfo* NewLineInfo (const LineInfoKey* Key)
181 /* Create and return a new line info. Usage will be zero. */
183 /* Allocate memory */
184 LineInfo* LI = xmalloc (sizeof (LineInfo));
186 /* Initialize the fields */
187 InitHashNode (&LI->Node);
192 InitCollection (&LI->Spans);
193 InitCollection (&LI->OpenSpans);
195 /* Return the new struct */
201 static void FreeLineInfo (LineInfo* LI)
202 /* Free a LineInfo structure */
204 /* Free the Spans collection. It is supposed to be empty */
205 CHECK (CollCount (&LI->Spans) == 0);
206 DoneCollection (&LI->Spans);
207 DoneCollection (&LI->OpenSpans);
209 /* Free the structure itself */
215 static void RememberLineInfo (LineInfo* LI)
216 /* Remember a LineInfo by adding it to the hash table and the global list.
217 * This will also assign the id which is actually the list position.
221 LI->Id = CollCount (&LineInfoList);
223 /* Remember it in the global list */
224 CollAppend (&LineInfoList, LI);
226 /* Add it to the hash table, so we will find it if necessary */
227 HT_InsertEntry (&LineInfoTab, LI);
229 /* Remember that we have it */
235 /*****************************************************************************/
237 /*****************************************************************************/
241 void InitLineInfo (void)
242 /* Initialize the line infos */
244 static const FilePos DefaultPos = STATIC_FILEPOS_INITIALIZER;
246 /* Increase the initial count of the line info collection */
247 CollGrow (&LineInfoList, 200);
249 /* Create a LineInfo for the default source. This is necessary to allow
250 * error message to be generated without any input file open.
252 AsmLineInfo = StartLine (&DefaultPos, LI_TYPE_ASM, 0);
257 void DoneLineInfo (void)
258 /* Close down line infos */
260 /* Close all current line infos */
261 unsigned Count = CollCount (&CurLineInfo);
263 EndLine (CollAt (&CurLineInfo, --Count));
269 void EndLine (LineInfo* LI)
270 /* End a line that is tracked by the given LineInfo structure */
274 /* Close the spans for the line */
275 CloseSpans (&LI->OpenSpans);
277 /* Move the spans to the list of all spans for this line, then clear the
278 * list of open spans.
280 for (I = 0; I < CollCount (&LI->OpenSpans); ++I) {
281 CollAppend (&LI->Spans, CollAtUnchecked (&LI->OpenSpans, I));
283 CollDeleteAll (&LI->OpenSpans);
285 /* Line info is no longer active - remove it from the list of current
288 CollDeleteItem (&CurLineInfo, LI);
290 /* If this line info is already hashed, we're done. Otherwise, if it is
291 * marked as referenced or has non empty spans, remember it. It it is not
292 * referenced or doesn't have open spans, delete it.
295 if (LI->Referenced || CollCount (&LI->Spans) > 0) {
296 RememberLineInfo (LI);
305 LineInfo* StartLine (const FilePos* Pos, unsigned Type, unsigned Count)
306 /* Start line info for a new line */
311 /* Prepare the key struct */
316 /* Try to find a line info with this position and type in the hash table.
317 * If so, reuse it. Otherwise create a new one.
319 LI = HT_FindEntry (&LineInfoTab, &Key);
321 /* Allocate a new LineInfo */
322 LI = NewLineInfo (&Key);
327 /* Open the spans for this line info */
328 OpenSpans (&LI->OpenSpans);
330 /* Add the line info to the list of current line infos */
331 CollAppend (&CurLineInfo, LI);
333 /* Return the new info */
339 void NewAsmLine (void)
340 /* Start a new assembler input line. Use this function when generating new
341 * line of LI_TYPE_ASM. It will check if line and/or file have actually
342 * changed, end the old and start the new line as necessary.
345 /* Check if we can reuse the old line */
347 if (AsmLineInfo->Key.Pos.Line == CurTok.Pos.Line &&
348 AsmLineInfo->Key.Pos.Name == CurTok.Pos.Name) {
349 /* We do already have line info for this line */
353 /* Line has changed -> end the old line */
354 EndLine (AsmLineInfo);
357 /* Start a new line using the current line info */
358 AsmLineInfo = StartLine (&CurTok.Pos, LI_TYPE_ASM, 0);
363 void GetFullLineInfo (Collection* LineInfos, int ForceRef)
364 /* Return full line infos, that is line infos for currently active Slots. The
365 * function will clear LineInfos before usage. If ForceRef is not zero, a
366 * forced reference will be added to all line infos, with the consequence that
367 * they won't get deleted, even if there is no code or data generated for these
373 /* Clear the collection */
374 CollDeleteAll (LineInfos);
376 /* Grow the collection as necessary */
377 CollGrow (LineInfos, CollCount (&CurLineInfo));
379 /* Copy all valid line infos to the collection */
380 for (I = 0; I < CollCount (&CurLineInfo); ++I) {
382 /* Get the line info from the slot */
383 LineInfo* LI = CollAt (&CurLineInfo, I);
385 /* Mark it as referenced */
390 /* Return it to the caller */
391 CollAppend (LineInfos, LI);
397 const FilePos* GetSourcePos (const LineInfo* LI)
398 /* Return the source file position from the given line info */
405 unsigned GetLineInfoType (const LineInfo* LI)
406 /* Return the type of a line info */
408 return LI_GET_TYPE (LI->Key.Type);
413 void WriteLineInfo (const Collection* LineInfos)
414 /* Write a list of line infos to the object file. */
418 /* Write the count */
419 ObjWriteVar (CollCount (LineInfos));
421 /* Write the line info indices */
422 for (I = 0; I < CollCount (LineInfos); ++I) {
424 /* Get a pointer to the line info */
425 const LineInfo* LI = CollConstAt (LineInfos, I);
427 CHECK (LI->Id != ~0U);
429 /* Write the index to the file */
430 ObjWriteVar (LI->Id);
436 void WriteLineInfos (void)
437 /* Write a list of all line infos to the object file. */
441 /* Tell the object file module that we're about to write line infos */
442 ObjStartLineInfos ();
444 /* Write the line info count to the list */
445 ObjWriteVar (CollCount (&LineInfoList));
447 /* Walk over the list and write all line infos */
448 for (I = 0; I < CollCount (&LineInfoList); ++I) {
450 /* Get a pointer to this line info */
451 LineInfo* LI = CollAt (&LineInfoList, I);
453 /* Write the source file position */
454 ObjWritePos (&LI->Key.Pos);
456 /* Write the type and count of the line info */
457 ObjWriteVar (LI_MAKE_TYPE (LI->Key.Type, LI->Key.Count));
459 /* Write the spans for this line */
460 WriteSpans (&LI->Spans);
463 /* End of line infos */