]> git.sur5r.net Git - cc65/blob - src/ca65/ulabel.c
c63e7e10af07962a309529c5465d60853ec3bb6d
[cc65] / src / ca65 / ulabel.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 ulabel.c                                  */
4 /*                                                                           */
5 /*                Unnamed labels for the ca65 macroassembler                 */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2000-2003 Ullrich von Bassewitz                                       */
10 /*               Römerstrasse 52                                             */
11 /*               D-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 /* common */
37 #include "check.h"
38 #include "filepos.h"
39 #include "xmalloc.h"
40
41 /* ca65 */
42 #include "error.h"
43 #include "expr.h"
44 #include "scanner.h"
45 #include "ulabel.h"
46
47
48
49 /*****************************************************************************/
50 /*                                   Data                                    */
51 /*****************************************************************************/
52
53
54
55 /* Struct that describes an unnamed label */
56 typedef struct ULabel ULabel;
57 struct ULabel {
58     ULabel*     Prev;                   /* Pointer to previous node in list */
59     ULabel*     Next;                   /* Pointer to next node in list */
60     FilePos     Pos;                    /* Position of the label in the source */
61     ExprNode*   Val;                    /* The label value - may be NULL */
62 };
63
64 /* List management */
65 static ULabel*  ULabRoot        = 0;    /* Root of the list */
66 static ULabel*  ULabLast        = 0;    /* Last ULabel */
67 static ULabel*  ULabLastDef     = 0;    /* Last defined ULabel */
68 static unsigned ULabCount       = 0;    /* Number of labels */
69 static unsigned ULabDefCount    = 0;    /* Number of defined labels */
70 static ULabel** ULabList        = 0;    /* Array with pointers to all labels */
71
72
73
74 /*****************************************************************************/
75 /*                                   Code                                    */
76 /*****************************************************************************/
77
78
79
80 static ULabel* NewULabel (ExprNode* Val)
81 /* Create a new ULabel and insert it into the list. The function will move
82  * ULabelLast, but not ULabelLastDef. The created label structure is returned.
83  */
84 {
85     /* Allocate memory for the ULabel structure */
86     ULabel* L = xmalloc (sizeof (ULabel));
87
88     /* Initialize the fields */
89     L->Pos = CurPos;
90     L->Val = Val;
91
92     /* Insert the label into the list */
93     L->Next = 0;
94     if (ULabRoot == 0) {
95         /* First label */
96         L->Prev = 0;
97         ULabRoot = L;
98     } else {
99         ULabLast->Next = L;
100         L->Prev = ULabLast;
101     }
102     ULabLast = L;
103
104     /* One label more */
105     ++ULabCount;
106
107     /* Return the created label */
108     return L;
109 }
110
111
112
113 ExprNode* ULabRef (int Which)
114 /* Get an unnamed label. If Which is negative, it is a backreference (a
115  * reference to an already defined label), and the function will return a
116  * segment relative expression. If Which is positive, it is a forward ref,
117  * and the function will return a expression node for an unnamed label that
118  * must be resolved later.
119  */
120 {
121     ULabel* L;
122
123     /* Which can never be 0 */
124     PRECONDITION (Which != 0);
125
126     /* Which is never really big (usually -3..+3), so a linear search is
127      * the best we can do here.
128      */
129     L = ULabLastDef;
130     if (Which < 0) {
131         /* Backward reference */
132         while (Which < -1 && L != 0) {
133             L = L->Prev;
134             ++Which;
135         }
136         if (L == 0) {
137             /* Label does not exist */
138             Error (ERR_UNDEFINED_LABEL);
139             /* We must return something valid */
140             return GenCurrentPC();
141         } else {
142             /* Return a copy of the label value */
143             return CloneExpr (L->Val);
144         }
145     } else {
146         /* Forward reference. Create labels as needed */
147         unsigned LabelNum = ULabDefCount + Which - 1;
148         while (LabelNum < ULabCount) {
149             NewULabel (0);
150         }
151
152         /* Return an unnamed label expression */
153         return GenULabelExpr (LabelNum);
154     }
155 }
156
157
158
159 void ULabDef (void)
160 /* Define an unnamed label at the current PC */
161 {
162     /* Create a new label if needed, or use an existing one */
163     if (ULabLastDef == 0 || ULabLastDef->Next == 0) {
164         /* The last label is also the last defined label, we need a new one */
165         ULabLastDef = NewULabel (GenCurrentPC ());
166     } else {
167         /* We do already have the label, but it's undefined until now */
168         ULabLastDef = ULabLastDef->Next;
169         ULabLastDef->Val = GenCurrentPC ();
170         ULabLastDef->Pos = CurPos;
171     }
172     ++ULabDefCount;
173 }
174
175
176
177 int ULabCanResolve (void)
178 /* Return true if we can resolve arbitrary ULabels. */
179 {
180     /* We can resolve labels if we have built the necessary access array */
181     return (ULabList != 0);
182 }
183
184
185
186 ExprNode* ULabResolve (unsigned Index)
187 /* Return a valid expression for the unnamed label with the given index. This
188  * is used to resolve unnamed labels when assembly is done, so it is an error
189  * if a label is still undefined in this phase.
190  */
191 {
192     ULabel* L;
193
194     /* Must be in resolve phase and the index must be valid */
195     CHECK (ULabList != 0 && Index < ULabCount);
196
197     /* Get the label */
198     L = ULabList [Index];
199
200     /* If the label is open (not defined), return some valid value */
201     if (L->Val == 0) {
202         return GenLiteralExpr (0);
203     } else {
204         return CloneExpr (L->Val);
205     }
206 }
207
208
209
210 void ULabCheck (void)
211 /* Run through all unnamed labels and check for anomalies and errors */
212 {
213     ULabel* L;
214
215     /* Check if there are undefined labels */
216     if (ULabLastDef) {
217         L = ULabLastDef->Next;
218         while (L) {
219             PError (&L->Pos, ERR_UNDEFINED_LABEL);
220             L = L->Next;
221         }
222     }
223
224     /* Create an array that holds pointers to all labels. This allows us to
225      * access the labels quickly by index in the resolver phase at the end of
226      * the assembly.
227      */
228     if (ULabCount) {
229         unsigned I = 0;
230         ULabList = xmalloc (ULabCount * sizeof (ULabel*));
231         L = ULabRoot;
232         while (L) {
233             ULabList[I] = L;
234             ++I;
235             L = L->Next;
236         }
237         CHECK (I == ULabCount);
238     }
239 }
240
241
242