1/*****************************************************************************/
2/* */
3/* toklist.c */
4/* */
5/* Token list for the ca65 macroassembler */
6/* */
7/* */
8/* */
9/* (C) 1998-2012, 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#include <string.h>
37
38/* common */
39#include "check.h"
40#include "xmalloc.h"
41
42/* ca65 */
43#include "error.h"
44#include "istack.h"
45#include "lineinfo.h"
46#include "nexttok.h"
47#include "scanner.h"
48#include "toklist.h"
49
50
51
52/*****************************************************************************/
53/* Data */
54/*****************************************************************************/
55
56
57
58/* Number of currently pushed token lists */
59static unsigned PushCounter = 0;
60
61
62
63/*****************************************************************************/
64/* Code */
65/*****************************************************************************/
66
67
68
69TokNode* NewTokNode (void)
70/* Create and return a token node with the current token value */
71{
72
73 /* Allocate memory */
74 TokNode* N = xmalloc (sizeof (TokNode));
75
76 /* Initialize the token contents */
77 N->Next = 0;
78 SB_Init (&N->T.SVal);
79 CopyToken (&N->T, &CurTok);
80
81 /* Return the node */
82 return N;
83}
84
85
86
87void FreeTokNode (TokNode* N)
88/* Free the given token node */
89{
90 SB_Done (&N->T.SVal);
91 xfree (N);
92}
93
94
95
96void TokSet (TokNode* N)
97/* Set the scanner token from the given token node. */
98{
99 /* Set the values */
100 CopyToken (&CurTok, &N->T);
101 SB_Terminate (&CurTok.SVal);
102}
103
104
105
106enum TC TokCmp (const TokNode* N)
107/* Compare the token given as parameter against the current token */
108{
109 if (N->T.Tok != CurTok.Tok) {
110 /* Different token */
111 return tcDifferent;
112 }
113
114 /* If the token has string attribute, check it */
115 if (TokHasSVal (N->T.Tok)) {
116 if (SB_Compare (&CurTok.SVal, &N->T.SVal) != 0) {
117 return tcSameToken;
118 }
119 } else if (TokHasIVal (N->T.Tok)) {
120 if (N->T.IVal != CurTok.IVal) {
121 return tcSameToken;
122 }
123 }
124
125 /* Tokens are identical */
126 return tcIdentical;
127}
128
129
130
131TokList* NewTokList (void)
132/* Create a new, empty token list */
133{
134 /* Allocate memory for the list structure */
135 TokList* T = xmalloc (sizeof (TokList));
136
137 /* Initialize the fields */
138 T->Next = 0;
139 T->Root = 0;
140 T->Last = 0;
141 T->RepCount = 0;
142 T->RepMax = 1;
143 T->Count = 0;
144 T->Check = 0;
145 T->Data = 0;
146 T->LI = 0;
147
148 /* Return the new list */
149 return T;
150}
151
152
153
154void FreeTokList (TokList* List)
155/* Delete the token list including all token nodes */
156{
157 /* Free the token list */
158 TokNode* T = List->Root;
159 while (T) {
160 TokNode* Tmp = T;
161 T = T->Next;
162 FreeTokNode (Tmp);
163 }
164
165 /* Free associated line info */
166 if (List->LI) {
167 EndLine (List->LI);
168 }
169
170 /* If we have associated data, free it */
171 if (List->Data) {
172 xfree (List->Data);
173 }
174
175 /* Free the list structure itself */
176 xfree (List);
177}
178
179
180
181enum token_t GetTokListTerm (enum token_t Term)
182/* Determine if the following token list is enclosed in curly braces. This is
183** the case if the next token is the opening brace. If so, skip it and return
184** a closing brace, otherwise return Term.
185*/
186{
187 if (CurTok.Tok == TOK_LCURLY) {
188 NextTok ();
189 return TOK_RCURLY;
190 } else {
191 return Term;
192 }
193}
194
195
196
197void AddCurTok (TokList* List)
198/* Add the current token to the token list */
199{
200 /* Create a token node with the current token value */
201 TokNode* T = NewTokNode ();
202
203 /* Insert the node into the list */
204 if (List->Root == 0) {
205 List->Root = T;
206 } else {
207 List->Last->Next = T;
208 }
209 List->Last = T;
210
211 /* Count nodes */
212 List->Count++;
213}
214
215
216
217static int ReplayTokList (void* List)
218/* Function that gets the next token from a token list and sets it. This
219** function may be used together with the PushInput function from the istack
220** module.
221*/
222{
223 /* Cast the generic pointer to an actual list */
224 TokList* L = List;
225
226 /* If there are no more tokens, decrement the repeat counter. If it goes
227 ** zero, delete the list and remove the function from the stack.
228 */
229 if (L->Last == 0) {
230 if (++L->RepCount >= L->RepMax) {
231 /* Done with this list */
232 FreeTokList (L);
233 --PushCounter;
234 PopInput ();
235 return 0;
236 } else {
237 /* Replay one more time */
238 L->Last = L->Root;
239 }
240 }
241
242 /* Set the next token from the list */
243 TokSet (L->Last);
244
245 /* Set the line info for the new token */
246 if (L->LI) {
247 EndLine (L->LI);
248 }
249 L->LI = StartLine (&CurTok.Pos, LI_TYPE_ASM, PushCounter);
250
251 /* If a check function is defined, call it, so it may look at the token
252 ** just set and changed it as apropriate.
253 */
254 if (L->Check) {
255 L->Check (L);
256 }
257
258 /* Set the pointer to the next token */
259 L->Last = L->Last->Next;
260
261 /* We have a token */
262 return 1;
263}
264
265
266
267void PushTokList (TokList* List, const char* Desc)
268/* Push a token list to be used as input for InputFromStack. This includes
269** several initializations needed in the token list structure, so don't use
270** PushInput directly.
271*/
272{
273 /* If the list is empty, just delete it and bail out */
274 if (List->Count == 0) {
275 FreeTokList (List);
276 return;
277 }
278
279 /* Reset the last pointer to the first element */
280 List->Last = List->Root;
281
282 /* Insert the list specifying our input function */
283 ++PushCounter;
284 PushInput (ReplayTokList, List, Desc);
285}
286