1/*****************************************************************************/
2/* */
3/* ulabel.c */
4/* */
5/* Unnamed labels for the ca65 macroassembler */
6/* */
7/* */
8/* */
9/* (C) 2000-2011, Ullrich von Bassewitz */
10/* Roemerstrasse 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 "coll.h"
39#include "xmalloc.h"
40
41/* ca65 */
42#include "error.h"
43#include "expr.h"
44#include "lineinfo.h"
45#include "scanner.h"
46#include "ulabel.h"
47
48
49
50/*****************************************************************************/
51/* Data */
52/*****************************************************************************/
53
54
55
56/* Struct that describes an unnamed label */
57typedef struct ULabel ULabel;
58struct ULabel {
59 Collection LineInfos; /* Position of the label in the source */
60 ExprNode* Val; /* The label value - may be NULL */
61 unsigned Ref; /* Number of references */
62};
63
64/* List management */
65static Collection ULabList = STATIC_COLLECTION_INITIALIZER;
66static unsigned ULabDefCount = 0; /* Number of defined labels */
67
68
69
70/*****************************************************************************/
71/* Code */
72/*****************************************************************************/
73
74
75
76static ULabel* NewULabel (ExprNode* Val)
77/* Create a new ULabel and insert it into the collection. The created label
78** structure is returned.
79*/
80{
81 /* Allocate memory for the ULabel structure */
82 ULabel* L = xmalloc (sizeof (ULabel));
83
84 /* Initialize the fields */
85 L->LineInfos = EmptyCollection;
86 GetFullLineInfo (&L->LineInfos);
87 L->Val = Val;
88 L->Ref = 0;
89
90 /* Insert the label into the collection */
91 CollAppend (&ULabList, L);
92
93 /* Return the created label */
94 return L;
95}
96
97
98
99ExprNode* ULabRef (int Which)
100/* Get an unnamed label. If Which is negative, it is a backreference (a
101** reference to an already defined label), and the function will return a
102** segment relative expression. If Which is positive, it is a forward ref,
103** and the function will return a expression node for an unnamed label that
104** must be resolved later.
105*/
106{
107 int Index;
108 ULabel* L;
109
110 /* Which can never be 0 */
111 PRECONDITION (Which != 0);
112
113 /* Get the index of the referenced label */
114 if (Which > 0) {
115 --Which;
116 }
117 Index = (int) ULabDefCount + Which;
118
119 /* We cannot have negative label indices */
120 if (Index < 0) {
121 /* Label does not exist */
122 Error ("Undefined label");
123 /* We must return something valid */
124 return GenCurrentPC();
125 }
126
127 /* Check if the label exists. If not, generate enough forward labels. */
128 if (Index < (int) CollCount (&ULabList)) {
129 /* The label exists, get it. */
130 L = CollAtUnchecked (&ULabList, Index);
131 } else {
132 /* Generate new, undefined labels */
133 while (Index >= (int) CollCount (&ULabList)) {
134 L = NewULabel (0);
135 }
136 }
137
138 /* Mark the label as referenced */
139 ++L->Ref;
140
141 /* If the label is already defined, return its value, otherwise return
142 ** just a reference.
143 */
144 if (L->Val) {
145 return CloneExpr (L->Val);
146 } else {
147 return GenULabelExpr (Index);
148 }
149}
150
151
152
153void ULabDef (void)
154/* Define an unnamed label at the current PC */
155{
156 if (ULabDefCount < CollCount (&ULabList)) {
157 /* We did already have a forward reference to this label, so has
158 ** already been generated, but doesn't have a value. Use the current
159 ** PC for the label value.
160 */
161 ULabel* L = CollAtUnchecked (&ULabList, ULabDefCount);
162 CHECK (L->Val == 0);
163 L->Val = GenCurrentPC ();
164 ReleaseFullLineInfo (&L->LineInfos);
165 GetFullLineInfo (&L->LineInfos);
166 } else {
167 /* There is no such label, create it */
168 NewULabel (GenCurrentPC ());
169 }
170
171 /* We have one more defined label */
172 ++ULabDefCount;
173}
174
175
176
177int ULabCanResolve (void)
178/* Return true if we can resolve arbitrary ULabels. */
179{
180 /* We can resolve labels if we don't have any undefineds */
181 return (ULabDefCount == CollCount (&ULabList));
182}
183
184
185
186ExprNode* 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 /* Get the label and check that it is defined */
193 ULabel* L = CollAt (&ULabList, Index);
194 CHECK (L->Val != 0);
195
196 /* Return the label value */
197 return CloneExpr (L->Val);
198}
199
200
201
202void ULabDone (void)
203/* Run through all unnamed labels, check for anomalies and errors and do
204** necessary cleanups.
205*/
206{
207 /* Check if there are undefined labels */
208 unsigned I = ULabDefCount;
209 while (I < CollCount (&ULabList)) {
210 ULabel* L = CollAtUnchecked (&ULabList, I);
211 LIError (&L->LineInfos, "Undefined label");
212 ++I;
213 }
214
215 /* Walk over all labels and emit a warning if any unreferenced ones
216 ** are found. Remove line infos because they're no longer needed.
217 */
218 for (I = 0; I < CollCount (&ULabList); ++I) {
219 ULabel* L = CollAtUnchecked (&ULabList, I);
220 if (L->Ref == 0) {
221 LIWarning (&L->LineInfos, 1, "No reference to unnamed label");
222 }
223 ReleaseFullLineInfo (&L->LineInfos);
224 }
225}
226