]> git.sur5r.net Git - cc65/blob - src/ca65/nexttok.c
Address size fixes
[cc65] / src / ca65 / nexttok.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 nexttok.c                                 */
4 /*                                                                           */
5 /*              Get next token and handle token level functions              */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2000-2003 Ullrich von Bassewitz                                       */
10 /*               Römerstraße 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 <stdio.h>
37 #include <string.h>
38
39 /* common */
40 #include "check.h"
41
42 /* ca65 */
43 #include "error.h"
44 #include "expr.h"
45 #include "scanner.h"
46 #include "toklist.h"
47 #include "nexttok.h"
48
49
50
51 /*****************************************************************************/
52 /*                                   Data                                    */
53 /*****************************************************************************/
54
55
56
57 static unsigned RawMode = 0;            /* Raw token mode flag/counter */
58
59
60
61 /*****************************************************************************/
62 /*                                   Code                                    */
63 /*****************************************************************************/
64
65
66
67 static TokList* CollectTokens (unsigned Start, unsigned Count)
68 /* Read a list of tokens that is terminated by a right paren. For all tokens
69  * starting at the one with index Start, and ending at (Start+Count-1), place
70  * them into a token list, and return this token list.
71  */
72 {
73     /* Create the token list */
74     TokList* List = NewTokList ();
75
76     /* Read the token list */
77     unsigned Current = 0;
78     unsigned Parens  = 0;
79     while (Parens != 0 || Tok != TOK_RPAREN) {
80
81         /* Check for end of line or end of input */
82         if (TokIsSep (Tok)) {
83             Error ("Unexpected end of line");
84             return List;
85         }
86
87         /* Collect tokens in the given range */
88         if (Current >= Start && Current < Start+Count) {
89             /* Add the current token to the list */
90             AddCurTok (List);
91         }
92
93         /* Check for and count parenthesii */
94         if (Tok == TOK_LPAREN) {
95             ++Parens;
96         } else if (Tok == TOK_RPAREN) {
97             --Parens;
98         }
99
100         /* Get the next token */
101         ++Current;
102         NextTok ();
103     }
104
105     /* Eat the closing paren */
106     ConsumeRParen ();
107
108     /* Return the list of collected tokens */
109     return List;
110 }
111
112
113
114 static void FuncConcat (void)
115 /* Handle the .CONCAT function */
116 {
117     char        Buf[MAX_STR_LEN+1];
118     char*       B;
119     unsigned    Length;
120     unsigned    L;
121
122     /* Skip it */
123     NextTok ();
124
125     /* Left paren expected */
126     ConsumeLParen ();
127
128     /* Concatenate any number of strings */
129     B = Buf;
130     B[0] = '\0';
131     Length = 0;
132     while (1) {
133
134         /* Next token must be a string */
135         if (Tok != TOK_STRCON) {
136             Error ("String constant expected");
137             SkipUntilSep ();
138             return;
139         }
140
141         /* Get the length of the string const and check total length */
142         L = strlen (SVal);
143         if (Length + L > MAX_STR_LEN) {
144             Error ("String is too long");
145             /* Try to recover */
146             SkipUntilSep ();
147             return;
148         }
149
150         /* Add the new string */
151         memcpy (B, SVal, L);
152         Length += L;
153         B      += L;
154
155         /* Skip the string token */
156         NextTok ();
157
158         /* Comma means another argument */
159         if (Tok == TOK_COMMA) {
160             NextTok ();
161         } else {
162             /* Done */
163             break;
164         }
165     }
166
167     /* Terminate the string */
168     *B = '\0';
169
170     /* We expect a closing parenthesis, but will not skip it but replace it
171      * by the string token just created.
172      */
173     if (Tok != TOK_RPAREN) {
174         Error ("`)' expected");
175     } else {
176         Tok = TOK_STRCON;
177         strcpy (SVal, Buf);
178     }
179 }
180
181
182
183 static void FuncLeft (void)
184 /* Handle the .LEFT function */
185 {
186     long        Count;
187     TokList*    List;
188
189     /* Skip it */
190     NextTok ();
191
192     /* Left paren expected */
193     ConsumeLParen ();
194
195     /* Count argument */
196     Count = ConstExpression ();
197     if (Count < 0 || Count > 100) {
198         Error ("Range error");
199         Count = 1;
200     }
201     ConsumeComma ();
202
203     /* Read the token list */
204     List = CollectTokens (0, (unsigned) Count);
205
206     /* Since we want to insert the list before the now current token, we have
207      * to save the current token in some way and then skip it. To do this, we
208      * will add the current token at the end of the token list (so the list
209      * will never be empty), push the token list, and then skip the current
210      * token. This will replace the current token by the first token from the
211      * list (which will be the old current token in case the list was empty).
212      */
213     AddCurTok (List);
214
215     /* Insert it into the scanner feed */
216     PushTokList (List, ".LEFT");
217
218     /* Skip the current token */
219     NextTok ();
220 }
221
222
223
224 static void FuncMid (void)
225 /* Handle the .MID function */
226 {
227     long        Start;
228     long        Count;
229     TokList*    List;
230
231     /* Skip it */
232     NextTok ();
233
234     /* Left paren expected */
235     ConsumeLParen ();
236
237     /* Start argument */
238     Start = ConstExpression ();
239     if (Start < 0 || Start > 100) {
240         Error ("Range error");
241         Start = 0;
242     }
243     ConsumeComma ();
244
245     /* Count argument */
246     Count = ConstExpression ();
247     if (Count < 0 || Count > 100) {
248         Error ("Range error");
249         Count = 1;
250     }
251     ConsumeComma ();
252
253     /* Read the token list */
254     List = CollectTokens ((unsigned) Start, (unsigned) Count);
255
256     /* Since we want to insert the list before the now current token, we have
257      * to save the current token in some way and then skip it. To do this, we
258      * will add the current token at the end of the token list (so the list
259      * will never be empty), push the token list, and then skip the current
260      * token. This will replace the current token by the first token from the
261      * list (which will be the old current token in case the list was empty).
262      */
263     AddCurTok (List);
264
265     /* Insert it into the scanner feed */
266     PushTokList (List, ".MID");
267
268     /* Skip the current token */
269     NextTok ();
270 }
271
272
273
274 static void FuncRight (void)
275 /* Handle the .RIGHT function */
276 {
277     long        Count;
278     TokList*    List;
279
280     /* Skip it */
281     NextTok ();
282
283     /* Left paren expected */
284     ConsumeLParen ();
285
286     /* Count argument */
287     Count = ConstExpression ();
288     if (Count < 0 || Count > 100) {
289         Error ("Range error");
290         Count = 1;
291     }
292     ConsumeComma ();
293
294     /* Read the complete token list */
295     List = CollectTokens (0, 9999);
296
297     /* Delete tokens from the list until Count tokens are remaining */
298     while (List->Count > (unsigned) Count) {
299         /* Get the first node */
300         TokNode* T = List->Root;
301
302         /* Remove it from the list */
303         List->Root = List->Root->Next;
304
305         /* Free the node */
306         FreeTokNode (T);
307
308         /* Corrent the token counter */
309         List->Count--;
310     }
311
312     /* Since we want to insert the list before the now current token, we have
313      * to save the current token in some way and then skip it. To do this, we
314      * will add the current token at the end of the token list (so the list
315      * will never be empty), push the token list, and then skip the current
316      * token. This will replace the current token by the first token from the
317      * list (which will be the old current token in case the list was empty).
318      */
319     AddCurTok (List);
320
321     /* Insert it into the scanner feed */
322     PushTokList (List, ".RIGHT");
323
324     /* Skip the current token */
325     NextTok ();
326 }
327
328
329
330 static void FuncString (void)
331 /* Handle the .STRING function */
332 {
333     char Buf[MAX_STR_LEN+1];
334
335     /* Skip it */
336     NextTok ();
337
338     /* Left paren expected */
339     ConsumeLParen ();
340
341     /* Accept identifiers or numeric expressions */
342     if (Tok == TOK_IDENT) {
343         /* Save the identifier, then skip it */
344         strcpy (Buf, SVal);
345         NextTok ();
346     } else {
347         /* Numeric expression */
348         long Val = ConstExpression ();
349         sprintf (Buf, "%ld", Val);
350     }
351
352     /* We expect a closing parenthesis, but will not skip it but replace it
353      * by the string token just created.
354      */
355     if (Tok != TOK_RPAREN) {
356         Error ("`)' expected");
357     } else {
358         Tok = TOK_STRCON;
359         strcpy (SVal, Buf);
360     }
361 }
362
363
364
365 void NextTok (void)
366 /* Get next token and handle token level functions */
367 {
368     /* Get the next raw token */
369     NextRawTok ();
370
371     /* In raw mode, pass the token unchanged */
372     if (RawMode == 0) {
373
374         /* Execute token handling functions */
375         switch (Tok) {
376
377             case TOK_CONCAT:
378                 FuncConcat ();
379                 break;
380
381             case TOK_LEFT:
382                 FuncLeft ();
383                 break;
384
385             case TOK_MID:
386                 FuncMid ();
387                 break;
388
389             case TOK_RIGHT:
390                 FuncRight ();
391                 break;
392
393             case TOK_STRING:
394                 FuncString ();
395                 break;
396
397             default:
398                 /* Quiet down gcc */
399                 break;
400
401         }
402     }
403 }
404
405
406
407 void Consume (enum Token Expected, const char* ErrMsg)
408 /* Consume Expected, print an error if we don't find it */
409 {
410     if (Tok == Expected) {
411         NextTok ();
412     } else {
413         Error (ErrMsg);
414     }
415 }
416
417
418
419 void ConsumeSep (void)
420 /* Consume a separator token */
421 {
422     /* Accept an EOF as separator */
423     if (Tok != TOK_EOF) {
424         if (Tok != TOK_SEP) {
425             Error ("Too many characters");
426             SkipUntilSep ();
427         } else {
428             NextTok ();
429         }
430     }
431 }
432
433
434
435 void ConsumeLParen (void)
436 /* Consume a left paren */
437 {
438     Consume (TOK_LPAREN, "`(' expected");
439 }
440
441
442
443 void ConsumeRParen (void)
444 /* Consume a right paren */
445 {
446     Consume (TOK_RPAREN, "`)' expected");
447 }
448
449
450
451 void ConsumeComma (void)
452 /* Consume a comma */
453 {
454     Consume (TOK_COMMA, "`,' expected");
455 }
456
457
458
459 void SkipUntilSep (void)
460 /* Skip tokens until we reach a line separator or end of file */
461 {
462     while (!TokIsSep (Tok)) {
463         NextTok ();
464     }
465 }
466
467
468
469 void EnterRawTokenMode (void)
470 /* Enter raw token mode. In raw mode, token handling functions are not
471  * executed, but the function tokens are passed untouched to the upper
472  * layer. Raw token mode is used when storing macro tokens for later
473  * use.
474  * Calls to EnterRawTokenMode and LeaveRawTokenMode may be nested.
475  */
476 {
477     ++RawMode;
478 }
479
480
481
482 void LeaveRawTokenMode (void)
483 /* Leave raw token mode. */
484 {
485     PRECONDITION (RawMode > 0);
486     --RawMode;
487 }
488
489
490