]> git.sur5r.net Git - cc65/blob - src/cc65/codeseg.c
Added line infos
[cc65] / src / cc65 / codeseg.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 codeseg.c                                 */
4 /*                                                                           */
5 /*                          Code segment structure                           */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2001      Ullrich von Bassewitz                                       */
10 /*               Wacholderweg 14                                             */
11 /*               D-70597 Stuttgart                                           */
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 <ctype.h>
38
39 /* common */
40 #include "chartype.h"
41 #include "check.h"
42 #include "global.h"
43 #include "hashstr.h"
44 #include "strutil.h"
45 #include "xmalloc.h"
46 #include "xsprintf.h"
47
48 /* cc65 */
49 #include "asmlabel.h"
50 #include "codeent.h"
51 #include "codeinfo.h"
52 #include "datatype.h"
53 #include "error.h"
54 #include "symentry.h"
55 #include "codeseg.h"
56
57
58
59 /*****************************************************************************/
60 /*                             Helper functions                              */
61 /*****************************************************************************/
62
63
64
65 static void MoveLabelsToPool (CodeSeg* S, CodeEntry* E)
66 /* Move the labels of the code entry E to the label pool of the code segment */
67 {
68     unsigned LabelCount = GetCodeLabelCount (E);
69     while (LabelCount--) {
70         CodeLabel* L = GetCodeLabel (E, LabelCount);
71         L->Flags &= ~LF_DEF;
72         L->Owner = 0;
73         CollAppend (&S->Labels, L);
74     }
75     CollDeleteAll (&E->Labels);
76 }
77
78
79
80 static CodeLabel* FindCodeLabel (CodeSeg* S, const char* Name, unsigned Hash)
81 /* Find the label with the given name. Return the label or NULL if not found */
82 {
83     /* Get the first hash chain entry */
84     CodeLabel* L = S->LabelHash[Hash];
85
86     /* Search the list */
87     while (L) {
88         if (strcmp (Name, L->Name) == 0) {
89             /* Found */
90             break;
91         }
92         L = L->Next;
93     }
94     return L;
95 }
96
97
98
99 static CodeLabel* NewCodeSegLabel (CodeSeg* S, const char* Name, unsigned Hash)
100 /* Create a new label and insert it into the label hash table */
101 {
102     /* Not found - create a new one */
103     CodeLabel* L = NewCodeLabel (Name, Hash);
104
105     /* Enter the label into the hash table */
106     L->Next = S->LabelHash[L->Hash];
107     S->LabelHash[L->Hash] = L;
108
109     /* Return the new label */
110     return L;
111 }
112
113
114
115 static void RemoveLabelFromHash (CodeSeg* S, CodeLabel* L)
116 /* Remove the given code label from the hash list */
117 {
118     /* Get the first entry in the hash chain */
119     CodeLabel* List = S->LabelHash[L->Hash];
120     CHECK (List != 0);
121
122     /* First, remove the label from the hash chain */
123     if (List == L) {
124         /* First entry in hash chain */
125         S->LabelHash[L->Hash] = L->Next;
126     } else {
127         /* Must search through the chain */
128         while (List->Next != L) {
129             /* If we've reached the end of the chain, something is *really* wrong */
130             CHECK (List->Next != 0);
131             /* Next entry */
132             List = List->Next;
133         }
134         /* The next entry is the one, we have been searching for */
135         List->Next = L->Next;
136     }
137 }
138
139
140
141 /*****************************************************************************/
142 /*                    Functions for parsing instructions                     */
143 /*****************************************************************************/
144
145
146
147 static const char* SkipSpace (const char* S)
148 /* Skip white space and return an updated pointer */
149 {
150     while (IsSpace (*S)) {
151         ++S;
152     }
153     return S;
154 }
155
156
157
158 static const char* ReadToken (const char* L, const char* Term,
159                               char* Buf, unsigned BufSize)
160 /* Read the next token into Buf, return the updated line pointer. The
161  * token is terminated by one of the characters given in term.
162  */
163 {
164     /* Read/copy the token */
165     unsigned I = 0;
166     unsigned ParenCount = 0;
167     while (*L && (ParenCount > 0 || strchr (Term, *L) == 0)) {
168         if (I < BufSize-1) {
169             Buf[I++] = *L;
170         }
171         if (*L == ')') {
172             --ParenCount;
173         } else if (*L == '(') {
174             ++ParenCount;
175         }
176         ++L;
177     }
178
179     /* Terminate the buffer contents */
180     Buf[I] = '\0';
181
182     /* Return the updated line pointer */
183     return L;
184 }
185
186
187
188 static CodeEntry* ParseInsn (CodeSeg* S, LineInfo* LI, const char* L)
189 /* Parse an instruction nnd generate a code entry from it. If the line contains
190  * errors, output an error message and return NULL.
191  * For simplicity, we don't accept the broad range of input a "real" assembler
192  * does. The instruction and the argument are expected to be separated by
193  * white space, for example.
194  */
195 {
196     char                Mnemo[16];
197     const OPCDesc*      OPC;
198     am_t                AM = 0;         /* Initialize to keep gcc silent */
199     char                Arg[64];
200     char                Reg;
201     CodeEntry*          E;
202     CodeLabel*          Label;
203
204     /* Mnemonic */
205     L = ReadToken (L, " \t", Mnemo, sizeof (Mnemo));
206
207     /* Try to find the opcode description for the mnemonic */
208     OPC = FindOpcode (Mnemo);
209
210     /* If we didn't find the opcode, print an error and bail out */
211     if (OPC == 0) {
212         Error ("ASM code error: %s is not a valid mnemonic", Mnemo);
213         return 0;
214     }
215
216     /* Skip separator white space */
217     L = SkipSpace (L);
218
219     /* Get the addressing mode */
220     Arg[0] = '\0';
221     switch (*L) {
222
223         case '\0':
224             /* Implicit */
225             AM = AM_IMP;
226             break;
227
228         case '#':
229             /* Immidiate */
230             StrCopy (Arg, sizeof (Arg), L+1);
231             AM = AM_IMM;
232             break;
233
234         case '(':
235             /* Indirect */
236             L = ReadToken (L+1, ",)", Arg, sizeof (Arg));
237
238             /* Check for errors */
239             if (*L == '\0') {
240                 Error ("ASM code error: syntax error");
241                 return 0;
242             }
243
244             /* Check the different indirect modes */
245             if (*L == ',') {
246                 /* Expect zp x indirect */
247                 L = SkipSpace (L+1);
248                 if (toupper (*L) != 'X') {
249                     Error ("ASM code error: `X' expected");
250                     return 0;
251                 }
252                 L = SkipSpace (L+1);
253                 if (*L != ')') {
254                     Error ("ASM code error: `)' expected");
255                     return 0;
256                 }
257                 L = SkipSpace (L+1);
258                 if (*L != '\0') {
259                     Error ("ASM code error: syntax error");
260                     return 0;
261                 }
262                 AM = AM_ZPX_IND;
263             } else if (*L == ')') {
264                 /* zp indirect or zp indirect, y */
265                 L = SkipSpace (L+1);
266                 if (*L == ',') {
267                     L = SkipSpace (L+1);
268                     if (toupper (*L) != 'Y') {
269                         Error ("ASM code error: `Y' expected");
270                         return 0;
271                     }
272                     L = SkipSpace (L+1);
273                     if (*L != '\0') {
274                         Error ("ASM code error: syntax error");
275                         return 0;
276                     }
277                     AM = AM_ZP_INDY;
278                 } else if (*L == '\0') {
279                     AM = AM_ZP_IND;
280                 } else {
281                     Error ("ASM code error: syntax error");
282                     return 0;
283                 }
284             }
285             break;
286
287         case 'a':
288         case 'A':
289             /* Accumulator? */
290             if (L[1] == '\0') {
291                 AM = AM_ACC;
292                 break;
293             }
294             /* FALLTHROUGH */
295
296         default:
297             /* Absolute, maybe indexed */
298             L = ReadToken (L, ",", Arg, sizeof (Arg));
299             if (*L == '\0') {
300                 /* Absolute, zeropage or branch */
301                 if ((OPC->Info & OF_BRA) != 0) {
302                     /* Branch */
303                     AM = AM_BRA;
304                 } else if (IsZPName (Arg)) {
305                     AM = AM_ZP;
306                 } else {
307                     AM = AM_ABS;
308                 }
309             } else if (*L == ',') {
310                 /* Indexed */
311                 L = SkipSpace (L+1);
312                 if (*L == '\0') {
313                     Error ("ASM code error: syntax error");
314                     return 0;
315                 } else {
316                     Reg = toupper (*L);
317                     L = SkipSpace (L+1);
318                     if (Reg == 'X') {
319                         if (IsZPName (Arg)) {
320                             AM = AM_ZPX;
321                         } else {
322                             AM = AM_ABSX;
323                         }
324                     } else if (Reg == 'Y') {
325                         AM = AM_ABSY;
326                     } else {
327                         Error ("ASM code error: syntax error");
328                         return 0;
329                     }
330                     if (*L != '\0') {
331                         Error ("ASM code error: syntax error");
332                         return 0;
333                     }
334                 }
335             }
336             break;
337
338     }
339
340     /* If the instruction is a branch, check for the label and generate it
341      * if it does not exist. Ignore anything but local labels here.
342      */
343     Label = 0;
344     if (AM == AM_BRA && Arg[0] == 'L') {
345
346         /* Generate the hash over the label, then search for the label */
347         unsigned Hash = HashStr (Arg) % CS_LABEL_HASH_SIZE;
348         Label = FindCodeLabel (S, Arg, Hash);
349
350         /* If we don't have the label, it's a forward ref - create it */
351         if (Label == 0) {
352             /* Generate a new label */
353             Label = NewCodeSegLabel (S, Arg, Hash);
354         }
355     }
356
357     /* We do now have the addressing mode in AM. Allocate a new CodeEntry
358      * structure and initialize it.
359      */
360     E = NewCodeEntry (OPC->OPC, AM, Arg, Label, LI);
361
362     /* Return the new code entry */
363     return E;
364 }
365
366
367
368 /*****************************************************************************/
369 /*                                   Code                                    */
370 /*****************************************************************************/
371
372
373
374 CodeSeg* NewCodeSeg (const char* SegName, SymEntry* Func)
375 /* Create a new code segment, initialize and return it */
376 {
377     unsigned I;
378
379     /* Allocate memory */
380     CodeSeg* S = xmalloc (sizeof (CodeSeg));
381
382     /* Initialize the fields */
383     S->SegName  = xstrdup (SegName);
384     S->Func     = Func;
385     InitCollection (&S->Entries);
386     InitCollection (&S->Labels);
387     for (I = 0; I < sizeof(S->LabelHash) / sizeof(S->LabelHash[0]); ++I) {
388         S->LabelHash[I] = 0;
389     }
390
391     /* If we have a function given, get the return type of the function.
392      * Assume ANY return type besides void will use the A and X registers.
393      */
394     if (S->Func && !IsTypeVoid (GetFuncReturn (Func->Type))) {
395         S->ExitRegs = REG_AX;
396     } else {
397         S->ExitRegs = REG_NONE;
398     }
399
400     /* Return the new struct */
401     return S;
402 }
403
404
405
406 void AddCodeEntry (CodeSeg* S, LineInfo* LI, const char* Format, va_list ap)
407 /* Add a line to the given code segment */
408 {
409     const char* L;
410     CodeEntry*  E;
411     char        Token[64];
412
413     /* Format the line */
414     char Buf [256];
415     xvsprintf (Buf, sizeof (Buf), Format, ap);
416
417     /* Skip whitespace */
418     L = SkipSpace (Buf);
419
420     /* Check which type of instruction we have */
421     E = 0;      /* Assume no insn created */
422     switch (*L) {
423
424         case '\0':
425             /* Empty line, just ignore it */
426             break;
427
428         case ';':
429             /* Comment or hint, ignore it for now */
430             break;
431
432         case '.':
433             /* Control instruction */
434             ReadToken (L, " \t", Token, sizeof (Token));
435             Error ("ASM code error: Pseudo instruction `%s' not supported", Token);
436             break;
437
438         default:
439             E = ParseInsn (S, LI, L);
440             break;
441     }
442
443     /* If we have a code entry, transfer the labels and insert it */
444     if (E) {
445
446         /* Transfer the labels if we have any */
447         unsigned I;
448         unsigned LabelCount = CollCount (&S->Labels);
449         for (I = 0; I < LabelCount; ++I) {
450
451             /* Get the label */
452             CodeLabel* L = CollAt (&S->Labels, I);
453
454             /* Attach it to the entry */
455             AttachCodeLabel (E, L);
456         }
457
458         /* Delete the transfered labels */
459         CollDeleteAll (&S->Labels);
460
461         /* Add the entry to the list of code entries in this segment */
462         CollAppend (&S->Entries, E);
463
464     }
465 }
466
467
468
469 void InsertCodeEntry (CodeSeg* S, struct CodeEntry* E, unsigned Index)
470 /* Insert the code entry at the index given. Following code entries will be
471  * moved to slots with higher indices.
472  */
473 {
474     /* Insert the entry into the collection */
475     CollInsert (&S->Entries, E, Index);
476 }
477
478
479
480 void DelCodeEntry (CodeSeg* S, unsigned Index)
481 /* Delete an entry from the code segment. This includes moving any associated
482  * labels, removing references to labels and even removing the referenced labels
483  * if the reference count drops to zero.
484  */
485 {
486     /* Get the code entry for the given index */
487     CodeEntry* E = GetCodeEntry (S, Index);
488
489     /* If the entry has a labels, we have to move this label to the next insn.
490      * If there is no next insn, move the label into the code segement label
491      * pool. The operation is further complicated by the fact that the next
492      * insn may already have a label. In that case change all reference to
493      * this label and delete the label instead of moving it.
494      */
495     unsigned Count = GetCodeLabelCount (E);
496     if (Count > 0) {
497
498         /* The instruction has labels attached. Check if there is a next
499          * instruction.
500          */
501         if (Index == GetCodeEntryCount (S)-1) {
502
503             /* No next instruction, move to the codeseg label pool */
504             MoveLabelsToPool (S, E);
505
506         } else {
507
508             /* There is a next insn, get it */
509             CodeEntry* N = GetCodeEntry (S, Index+1);
510
511             /* Move labels to the next entry */
512             MoveCodeLabels (S, E, N);
513
514         }
515     }
516
517     /* If this insn references a label, remove the reference. And, if the
518      * the reference count for this label drops to zero, remove this label.
519      */
520     if (E->JumpTo) {
521         /* Remove the reference */
522         RemoveCodeLabelRef (S, E);
523     }
524
525     /* Delete the pointer to the insn */
526     CollDelete (&S->Entries, Index);
527
528     /* Delete the instruction itself */
529     FreeCodeEntry (E);
530 }
531
532
533
534 void DelCodeEntries (CodeSeg* S, unsigned Start, unsigned Count)
535 /* Delete a range of code entries. This includes removing references to labels,
536  * labels attached to the entries and so on.
537  */
538 {
539     /* Start deleting the entries from the rear, because this involves less
540      * memory moving.
541      */
542     while (Count--) {
543         DelCodeEntry (S, Start + Count);
544     }
545 }
546
547
548
549 void MoveCodeEntry (CodeSeg* S, unsigned OldPos, unsigned NewPos)
550 /* Move an entry from one position to another. OldPos is the current position
551  * of the entry, NewPos is the new position of the entry.
552  */
553 {
554     /* Get the code entry and remove it from the collection */
555     CodeEntry* E = GetCodeEntry (S, OldPos);
556     CollDelete (&S->Entries, OldPos);
557
558     /* Correct NewPos if needed */
559     if (NewPos >= OldPos) {
560         /* Position has changed with removal */
561         --NewPos;
562     }
563
564     /* Now insert it at the new position */
565     CollInsert (&S->Entries, E, NewPos);
566 }
567
568
569
570 struct CodeEntry* GetNextCodeEntry (CodeSeg* S, unsigned Index)
571 /* Get the code entry following the one with the index Index. If there is no
572  * following code entry, return NULL.
573  */
574 {
575     if (Index >= CollCount (&S->Entries)-1) {
576         /* This is the last entry */
577         return 0;
578     } else {
579         /* Code entries left */
580         return CollAtUnchecked (&S->Entries, Index+1);
581     }
582 }
583
584
585
586 int GetCodeEntries (CodeSeg* S, struct CodeEntry** List,
587                     unsigned Start, unsigned Count)
588 /* Get Count code entries into List starting at index start. Return true if
589  * we got the lines, return false if not enough lines were available.
590  */
591 {
592     /* Check if enough entries are available */
593     if (Start + Count > CollCount (&S->Entries)) {
594         return 0;
595     }
596
597     /* Copy the entries */
598     while (Count--) {
599         *List++ = CollAtUnchecked (&S->Entries, Start++);
600     }
601
602     /* We have the entries */
603     return 1;
604 }
605
606
607
608 unsigned GetCodeEntryIndex (CodeSeg* S, struct CodeEntry* E)
609 /* Return the index of a code entry */
610 {
611     int Index = CollIndex (&S->Entries, E);
612     CHECK (Index >= 0);
613     return Index;
614 }
615
616
617
618 void AddCodeLabel (CodeSeg* S, const char* Name)
619 /* Add a code label for the next instruction to follow */
620 {
621     /* Calculate the hash from the name */
622     unsigned Hash = HashStr (Name) % CS_LABEL_HASH_SIZE;
623
624     /* Try to find the code label if it does already exist */
625     CodeLabel* L = FindCodeLabel (S, Name, Hash);
626
627     /* Did we find it? */
628     if (L) {
629         /* We found it - be sure it does not already have an owner */
630         CHECK (L->Owner == 0);
631     } else {
632         /* Not found - create a new one */
633         L = NewCodeSegLabel (S, Name, Hash);
634     }
635
636     /* Safety. This call is quite costly, but safety is better */
637     if (CollIndex (&S->Labels, L) >= 0) {
638         Internal ("AddCodeLabel: Label `%s' already defined", Name);
639     }
640
641     /* We do now have a valid label. Remember it for later */
642     CollAppend (&S->Labels, L);
643 }
644
645
646
647 CodeLabel* GenCodeLabel (CodeSeg* S, struct CodeEntry* E)
648 /* If the code entry E does already have a label, return it. Otherwise
649  * create a new label, attach it to E and return it.
650  */
651 {
652     CodeLabel* L;
653
654     if (CodeEntryHasLabel (E)) {
655
656         /* Get the label from this entry */
657         L = GetCodeLabel (E, 0);
658
659     } else {
660
661         /* Get a new name */
662         const char* Name = LocalLabelName (GetLocalLabel ());
663
664         /* Generate the hash over the name */
665         unsigned Hash = HashStr (Name) % CS_LABEL_HASH_SIZE;
666
667         /* Create a new label */
668         L = NewCodeSegLabel (S, Name, Hash);
669
670         /* Attach this label to the code entry */
671         AttachCodeLabel (E, L);
672
673     }
674
675     /* Return the label */
676     return L;
677 }
678
679
680
681 void DelCodeLabel (CodeSeg* S, CodeLabel* L)
682 /* Remove references from this label and delete it. */
683 {
684     unsigned Count, I;
685
686     /* First, remove the label from the hash chain */
687     RemoveLabelFromHash (S, L);
688
689     /* Remove references from insns jumping to this label */
690     Count = CollCount (&L->JumpFrom);
691     for (I = 0; I < Count; ++I) {
692         /* Get the insn referencing this label */
693         CodeEntry* E = CollAt (&L->JumpFrom, I);
694         /* Remove the reference */
695         E->JumpTo = 0;
696     }
697     CollDeleteAll (&L->JumpFrom);
698
699     /* Remove the reference to the owning instruction if it has one. The
700      * function may be called for a label without an owner when deleting
701      * unfinished parts of the code. This is unfortunate since it allows
702      * errors to slip through.
703      */
704     if (L->Owner) {
705         CollDeleteItem (&L->Owner->Labels, L);
706     }
707
708     /* All references removed, delete the label itself */
709     FreeCodeLabel (L);
710 }
711
712
713
714 void MergeCodeLabels (CodeSeg* S)
715 /* Merge code labels. That means: For each instruction, remove all labels but
716  * one and adjust references accordingly.
717  */
718 {
719     unsigned I;
720
721     /* Walk over all code entries */
722     unsigned EntryCount = GetCodeEntryCount (S);
723     for (I = 0; I < EntryCount; ++I) {
724
725         CodeLabel* RefLab;
726         unsigned   J;
727
728         /* Get a pointer to the next entry */
729         CodeEntry* E = GetCodeEntry (S, I);
730
731         /* If this entry has zero labels, continue with the next one */
732         unsigned LabelCount = GetCodeLabelCount (E);
733         if (LabelCount == 0) {
734             continue;
735         }
736
737         /* We have at least one label. Use the first one as reference label. */
738         RefLab = GetCodeLabel (E, 0);
739
740         /* Walk through the remaining labels and change references to these
741          * labels to a reference to the one and only label. Delete the labels
742          * that are no longer used. To increase performance, walk backwards
743          * through the list.
744          */
745         for (J = LabelCount-1; J >= 1; --J) {
746
747             /* Get the next label */
748             CodeLabel* L = GetCodeLabel (E, J);
749
750             /* Move all references from this label to the reference label */
751             MoveLabelRefs (L, RefLab);
752
753             /* Remove the label completely. */
754             DelCodeLabel (S, L);
755         }
756
757         /* The reference label is the only remaining label. Check if there
758          * are any references to this label, and delete it if this is not
759          * the case.
760          */
761         if (CollCount (&RefLab->JumpFrom) == 0) {
762             /* Delete the label */
763             DelCodeLabel (S, RefLab);
764         }
765     }
766 }
767
768
769
770 void MoveCodeLabels (CodeSeg* S, struct CodeEntry* Old, struct CodeEntry* New)
771 /* Move all labels from Old to New. The routine will move the labels itself
772  * if New does not have any labels, and move references if there is at least
773  * a label for new. If references are moved, the old label is deleted
774  * afterwards.
775  */
776 {
777     /* Get the number of labels to move */
778     unsigned OldLabelCount = GetCodeLabelCount (Old);
779
780     /* Does the new entry have itself a label? */
781     if (CodeEntryHasLabel (New)) {
782
783         /* The new entry does already have a label - move references */
784         CodeLabel* NewLabel = GetCodeLabel (New, 0);
785         while (OldLabelCount--) {
786
787             /* Get the next label */
788             CodeLabel* OldLabel = GetCodeLabel (Old, OldLabelCount);
789
790             /* Move references */
791             MoveLabelRefs (OldLabel, NewLabel);
792
793             /* Delete the label */
794             DelCodeLabel (S, OldLabel);
795
796         }
797
798     } else {
799
800         /* The new entry does not have a label, just move them */
801         while (OldLabelCount--) {
802
803             /* Move the label to the new entry */
804             MoveCodeLabel (GetCodeLabel (Old, OldLabelCount), New);
805
806         }
807
808     }
809 }
810
811
812
813 void RemoveCodeLabelRef (CodeSeg* S, struct CodeEntry* E)
814 /* Remove the reference between E and the label it jumps to. The reference
815  * will be removed on both sides and E->JumpTo will be 0 after that. If
816  * the reference was the only one for the label, the label will get
817  * deleted.
818  */
819 {
820     /* Get a pointer to the label and make sure it exists */
821     CodeLabel* L = E->JumpTo;
822     CHECK (L != 0);
823
824     /* Delete the entry from the label */
825     CollDeleteItem (&L->JumpFrom, E);
826
827     /* The entry jumps no longer to L */
828     E->JumpTo = 0;
829
830     /* If there are no more references, delete the label */
831     if (CollCount (&L->JumpFrom) == 0) {
832         DelCodeLabel (S, L);
833     }
834 }
835
836
837
838 void MoveCodeLabelRef (CodeSeg* S, struct CodeEntry* E, CodeLabel* L)
839 /* Change the reference of E to L instead of the current one. If this
840  * was the only reference to the old label, the old label will get
841  * deleted.
842  */
843 {
844     /* Get the old label */
845     CodeLabel* OldLabel = E->JumpTo;
846
847     /* Be sure that code entry references a label */
848     PRECONDITION (OldLabel != 0);
849
850     /* Remove the reference to our label */
851     RemoveCodeLabelRef (S, E);
852
853     /* Use the new label */
854     AddLabelRef (L, E);
855 }
856
857
858
859 void DelCodeSegAfter (CodeSeg* S, unsigned Last)
860 /* Delete all entries including the given one */
861 {
862     /* Get the number of entries in this segment */
863     unsigned Count = GetCodeEntryCount (S);
864
865     /* First pass: Delete all references to labels. If the reference count
866      * for a label drops to zero, delete it.
867      */
868     unsigned C = Count;
869     while (Last < C--) {
870
871         /* Get the next entry */
872         CodeEntry* E = GetCodeEntry (S, C);
873
874         /* Check if this entry has a label reference */
875         if (E->JumpTo) {
876             /* If the label is a label in the label pool and this is the last
877              * reference to the label, remove the label from the pool.
878              */
879             CodeLabel* L = E->JumpTo;
880             int Index = CollIndex (&S->Labels, L);
881             if (Index >= 0 && CollCount (&L->JumpFrom) == 1) {
882                 /* Delete it from the pool */
883                 CollDelete (&S->Labels, Index);
884             }
885
886             /* Remove the reference to the label */
887             RemoveCodeLabelRef (S, E);
888         }
889
890     }
891
892     /* Second pass: Delete the instructions. If a label attached to an
893      * instruction still has references, it must be references from outside
894      * the deleted area. Don't delete the label in this case, just make it
895      * ownerless and move it to the label pool.
896      */
897     C = Count;
898     while (Last < C--) {
899
900         /* Get the next entry */
901         CodeEntry* E = GetCodeEntry (S, C);
902
903         /* Check if this entry has a label attached */
904         if (CodeEntryHasLabel (E)) {
905             /* Move the labels to the pool and clear the owner pointer */
906             MoveLabelsToPool (S, E);
907         }
908
909         /* Delete the pointer to the entry */
910         CollDelete (&S->Entries, C);
911
912         /* Delete the entry itself */
913         FreeCodeEntry (E);
914     }
915 }
916
917
918
919 void OutputCodeSeg (const CodeSeg* S, FILE* F)
920 /* Output the code segment data to a file */
921 {
922     unsigned I;
923     const LineInfo* LI;
924
925     /* Get the number of entries in this segment */
926     unsigned Count = GetCodeEntryCount (S);
927
928     /* If the code segment is empty, bail out here */
929     if (Count == 0) {
930         return;
931     }
932
933     /* Output the segment directive */
934     fprintf (F, ".segment\t\"%s\"\n\n", S->SegName);
935
936     /* If this is a segment for a function, enter a function */
937     if (S->Func) {
938         fprintf (F, ".proc\t_%s\n\n", S->Func->Name);
939     }
940
941     /* Output all entries, prepended by the line information if it has changed */
942     LI = 0;
943     for (I = 0; I < Count; ++I) {
944         /* Get the next entry */
945         const CodeEntry* E = CollConstAt (&S->Entries, I);
946         /* Check if the line info has changed. If so, output the source line
947          * if the option is enabled and output debug line info if the debug
948          * option is enabled.
949          */
950         if (E->LI != LI) {
951             /* Line info has changed, remember the new line info */
952             LI = E->LI;
953
954             /* Add the source line as a comment */
955             if (AddSource) {
956                 fprintf (F, ";\n; %s\n;\n", LI->Line);
957             }
958
959             /* Add line debug info */
960             if (DebugInfo) {
961                 fprintf (F, "\t.dbg\tline, \"%s\", %u\n",
962                          GetInputName (LI), GetInputLine (LI));
963             }
964         }
965         /* Output the code */
966         OutputCodeEntry (E, F);
967     }
968
969     /* If debug info is enabled, terminate the last line number information */
970     if (DebugInfo) {
971         fprintf (F, "\t.dbg\tline\n");
972     }
973
974     /* If this is a segment for a function, leave the function */
975     if (S->Func) {
976         fprintf (F, "\n.endproc\n\n");
977     }
978 }
979
980
981
982
983
984
985