1/*****************************************************************************/
2/* */
3/* repeat.c */
4/* */
5/* Handle the .REPEAT pseudo instruction */
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#include <string.h>
37
38/* common */
39#include "xmalloc.h"
40
41/* ca65 */
42#include "error.h"
43#include "expr.h"
44#include "nexttok.h"
45#include "toklist.h"
46#include "repeat.h"
47
48
49
50/*****************************************************************************/
51/* Code */
52/*****************************************************************************/
53
54
55
56static TokList* CollectRepeatTokens (void)
57/* Collect all tokens inside the .REPEAT body in a token list and return
58** this list. In case of errors, NULL is returned.
59*/
60{
61 /* Create the token list */
62 TokList* List = NewTokList ();
63
64 /* Read the token list */
65 unsigned Repeats = 0;
66 while (Repeats != 0 || CurTok.Tok != TOK_ENDREP) {
67
68 /* Check for end of input */
69 if (CurTok.Tok == TOK_EOF) {
70 Error ("Unexpected end of file");
71 FreeTokList (List);
72 return 0;
73 }
74
75 /* Collect all tokens in the list */
76 AddCurTok (List);
77
78 /* Check for and count nested .REPEATs */
79 if (CurTok.Tok == TOK_REPEAT) {
80 ++Repeats;
81 } else if (CurTok.Tok == TOK_ENDREP) {
82 --Repeats;
83 }
84
85 /* Get the next token */
86 NextTok ();
87 }
88
89 /* Eat the closing .ENDREP */
90 NextTok ();
91
92 /* Return the list of collected tokens */
93 return List;
94}
95
96
97
98static void RepeatTokenCheck (TokList* L)
99/* Called each time a token from a repeat token list is set. Is used to check
100** for and replace identifiers that are the repeat counter.
101*/
102{
103 if (CurTok.Tok == TOK_IDENT &&
104 L->Data != 0 &&
105 SB_CompareStr (&CurTok.SVal, L->Data) == 0) {
106 /* Must replace by the repeat counter */
107 CurTok.Tok = TOK_INTCON;
108 CurTok.IVal = L->RepCount;
109 }
110}
111
112
113
114void ParseRepeat (void)
115/* Parse and handle the .REPEAT statement */
116{
117 char* Name;
118 TokList* List;
119
120 /* Repeat count follows */
121 long RepCount = ConstExpression ();
122 if (RepCount < 0) {
123 Error ("Range error");
124 RepCount = 0;
125 }
126
127 /* Optional there is a comma and a counter variable */
128 Name = 0;
129 if (CurTok.Tok == TOK_COMMA) {
130
131 /* Skip the comma */
132 NextTok ();
133
134 /* Check for an identifier */
135 if (CurTok.Tok != TOK_IDENT) {
136 ErrorSkip ("Identifier expected");
137 } else {
138 /* Remember the name and skip it */
139 SB_Terminate (&CurTok.SVal);
140 Name = xstrdup (SB_GetConstBuf (&CurTok.SVal));
141 NextTok ();
142 }
143 }
144
145 /* Switch to raw token mode, then skip the separator */
146 EnterRawTokenMode ();
147 ConsumeSep ();
148
149 /* Read the token list */
150 List = CollectRepeatTokens ();
151
152 /* If we had an error, bail out */
153 if (List == 0) {
154 xfree (Name);
155 goto Done;
156 }
157
158 /* Update the token list for replay */
159 List->RepMax = (unsigned) RepCount;
160 List->Data = Name;
161 List->Check = RepeatTokenCheck;
162
163 /* If the list is empty, or repeat count zero, there is nothing
164 ** to repeat.
165 */
166 if (List->Count == 0 || RepCount == 0) {
167 FreeTokList (List);
168 goto Done;
169 }
170
171 /* Read input from the repeat descriptor */
172 PushTokList (List, ".REPEAT");
173
174Done:
175 /* Switch out of raw token mode */
176 LeaveRawTokenMode ();
177}
178