ugBASIC 1.18
An isomorphic BASIC language compiler for retrocomputers
Loading...
Searching...
No Matches
begin_for.c
Go to the documentation of this file.
1/*****************************************************************************
2 * ugBASIC - an isomorphic BASIC language compiler for retrocomputers *
3 *****************************************************************************
4 * Copyright 2021-2026 Marco Spedaletti (asimov@mclink.it)
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *----------------------------------------------------------------------------
18 * Concesso in licenza secondo i termini della Licenza Apache, versione 2.0
19 * (la "Licenza"); è proibito usare questo file se non in conformità alla
20 * Licenza. Una copia della Licenza è disponibile all'indirizzo:
21 *
22 * http://www.apache.org/licenses/LICENSE-2.0
23 *
24 * Se non richiesto dalla legislazione vigente o concordato per iscritto,
25 * il software distribuito nei termini della Licenza è distribuito
26 * "COSÌ COM'È", SENZA GARANZIE O CONDIZIONI DI ALCUN TIPO, esplicite o
27 * implicite. Consultare la Licenza per il testo specifico che regola le
28 * autorizzazioni e le limitazioni previste dalla medesima.
29 ****************************************************************************/
30
31/****************************************************************************
32 * INCLUDE SECTION
33 ****************************************************************************/
34
35#include "../../ugbc.h"
36
37/****************************************************************************
38 * CODE SECTION
39 ****************************************************************************/
40
52/* <usermanual>
53@keyword FOR...NEXT
54
55@english
56
57The ''FOR...NEXT'' is a basic tool for executing a block of code a
58specified number of times. It is a control structure that creates a
59loop, which is a segment of code that is repeated until a certain
60condition is met. Once inside the loop, the index used to loop
61can be read and modified by the program as if it is a normal variable.
62
63Normally, the index counter is increased by 1 unit at every turn of a
64''FOR...NEXT'' loop. When the current value exceeds that of the last
65number specified, the loop is terminated. ''STEP'' is used to
66change the size of increase in the index value.
67
68It should be noted, however, that none of the terms of the loop
69must be considered constant. The loop, in fact, continues
70as long as the condition for which the index is
71included within the indicated limits is true. If these limits are expressed by
72variables or, more generally, expressions, these values ​​are recalculated
73at each turn, to ensure compliance with the limits. The variable
74index itself can be updated within the loop, and therefore
75it is possible to interrupt a cycle or continue it definitively,
76by operating on this variable. Finally, one can jump in and out
77of the loop, without problems.
78
79The ''FOR...NEXT'' loop is ideal for performing the same operation
80a specific number of times. It can be used to create tables of
81values, such as a multiplication table. It is often used in
82algorithms that require repeated calculations, such as calculating
83the factorial of a number. Generally speaking, you can use the
84''FOR...NEXT'' when you know the number of iterations in advance,
85want to perform a sequence of operations repetitively and you
86need a simple and effective control structure.
87
88@italian
89
90''FOR...NEXT'' è uno strumento di base per eseguire un blocco
91di codice un numero di volte specificato. È una struttura di
92controllo che crea un ciclo, ovvero un segmento di codice
93che viene ripetuto finché non viene soddisfatta una determinata
94condizione. Una volta all'interno del ciclo, l'indice utilizzato
95per il ciclo può essere letto e modificato dal programma come
96se fosse una variabile normale.
97
98Normalmente, il contatore dell'indice viene aumentato di 1 unità
99a ogni giro di un ciclo ''FOR...NEXT''. Quando il valore corrente
100supera quello dell'ultimo numero specificato, il ciclo viene terminato.
101''STEP'' viene utilizzato per modificare la dimensione dell'aumento
102del valore dell'indice.
103
104Si deve ad ogni modo notare che nessuno dei termini del ciclo
105deve essere considerato costante. Il loop, infatti, continua
106fintanto che è vera la condizione per cui l'indice si trova
107ricompreso nei limiti indicati. Se tali limiti sono espressi da
108variabili o, più in generale, espressioni, tali valori sono ricalcolati
109ad ogni giro, per garantire il rispetto dei limiti. La variabile
110indice stessa può essere aggiornata all'interno del loop, e quindi
111è possibile interrompere un ciclo o continuarlo in via definitiva,
112operando su tale variabile. Infine, si può saltare dentro e fuori
113il loop, senza problemi.
114
115Il ciclo ''FOR...NEXT'' è ideale per eseguire la stessa operazione
116un numero di volte specifico. Può essere utilizzato per creare
117tabelle di valori, come una tabella di moltiplicazione. Viene spesso
118utilizzato in algoritmi che richiedono calcoli ripetuti, come il
119calcolo del fattoriale di un numero. In generale, è possibile
120utilizzare ''FOR...NEXT'' quando si conosce in anticipo il numero
121di iterazioni, si desidera eseguire una sequenza di operazioni
122in modo ripetitivo e si necessita di una struttura di controllo
123semplice ed efficace.
124
125@syntax FOR var = start TO end [ STEP increment ]
126@syntax ...
127@syntax NEXT [var]
128
129@example i = 0
130@example FOR i = 1 TO 100 STEP 2
131@example PRINT i
132@example NEXT
133
134@usedInExample control_controlled_01.bas
135@usedInExample control_controlled_02.bas
136
137@seeAlso DO...LOOP
138@seeAlso WHILE...WEND
139@seeAlso REPEAT...UNTIL
140
141</usermanual> */
142
143void begin_for_prepare( Environment * _environment, char * _index ) {
144
146
147 Loop * loop = malloc( sizeof( Loop ) );
148 memset( loop, 0, sizeof( Loop ) );
149 loop->label = strdup( label );
150 loop->type = LT_FOR;
151 loop->next = _environment->loops;
152 _environment->loops = loop;
153
154 unsigned char beginForPrepareAfter[MAX_TEMPORARY_STORAGE]; sprintf(beginForPrepareAfter, "%sprepa", label );
155
156 cpu_jump( _environment, beginForPrepareAfter );
157
158 Variable * index = NULL;
159 if ( variable_exists( _environment, _index ) ) {
160 index = variable_retrieve( _environment, _index );
161 } else {
162 if ( _environment->optionExplicit ) {
164 }
165 index = variable_retrieve_or_define( _environment, _index, _environment->defaultVariableType, 0 );
166 }
167
168 loop->index = index;
169
170}
171
172void begin_for_from_prepare( Environment * _environment ) {
173
174 Loop * loop = _environment->loops;
175
176 unsigned char beginForFromPrepare[MAX_TEMPORARY_STORAGE]; sprintf(beginForFromPrepare, "%sprepfrom", loop->label );
177
178 cpu_label( _environment, beginForFromPrepare );
179
180}
181
182void begin_for_from_assign( Environment * _environment, char * _from ) {
183
184 Loop * loop = _environment->loops;
185
186 Variable * from = variable_retrieve( _environment, _from );
187 Variable * fromResident = variable_resident( _environment, loop->index->type, "(from)" );
188
189 if ( from->initializedByConstant ) {
190 variable_store( _environment, fromResident->name, from->value );
191 } else {
192 variable_move( _environment, from->name, fromResident->name );
193 }
194
195 cpu_return( _environment );
196
197 loop->from = from;
198 loop->from->locked = 1;
199 loop->fromResident = fromResident;
200 loop->fromResident->locked = 1;
201
202 loop->to = NULL;
203
204}
205
206void begin_for_to_prepare( Environment * _environment ) {
207
208 Loop * loop = _environment->loops;
209
210 unsigned char beginForToPrepare[MAX_TEMPORARY_STORAGE]; sprintf(beginForToPrepare, "%sprepto", loop->label );
211
212 cpu_label( _environment, beginForToPrepare );
213
214}
215
216void begin_for_to_assign( Environment * _environment, char * _to ) {
217
218 Loop * loop = _environment->loops;
219 Variable * to = variable_retrieve( _environment, _to );
220 Variable * toResident = variable_resident( _environment, loop->index->type, "(to)" );
221
222 if ( to->initializedByConstant ) {
223 variable_store( _environment, toResident->name, to->value );
224 } else {
225 variable_move( _environment, to->name, toResident->name );
226 }
227
228 cpu_return( _environment );
229
230 loop->to = to;
231 loop->to->locked = 1;
232 loop->toResident = toResident;
233 loop->toResident->locked = 1;
234
235}
236
237void begin_for_step_prepare( Environment * _environment ) {
238
239 Loop * loop = _environment->loops;
240
241 unsigned char beginForStepPrepare[MAX_TEMPORARY_STORAGE]; sprintf(beginForStepPrepare, "%sprepstep", loop->label );
242
243 cpu_label( _environment, beginForStepPrepare );
244
245}
246
247void begin_for_step_assign( Environment * _environment, char * _step ) {
248
249 Loop * loop = _environment->loops;
250
251 Variable * from = loop->fromResident;
252 Variable * to = loop->toResident;
253
254 // Calculate the maximum rappresentable size for the index, based on from and to.
255 int maxType = VT_MAX_BITWIDTH_TYPE( from->type, to->type );
256
257 Variable * stepResident = NULL;
258 if ( _step ) {
259 Variable * step = variable_retrieve( _environment, _step );
260 if ( VT_SIGNED( from->type ) || VT_SIGNED( to->type ) || VT_SIGNED( step->type ) ) {
261 maxType = VT_SIGN( maxType );
262 }
263 // In this version, the step is given
264 stepResident = variable_resident( _environment, maxType, "(step)" );
265
266 if ( step->initializedByConstant ) {
267 variable_store( _environment, stepResident->name, step->value );
268 } else {
269 variable_move( _environment, step->name, stepResident->name );
270 }
271 loop->step = step;
272 loop->step->locked = 1;
273 } else {
274 if ( VT_SIGNED( from->type ) || VT_SIGNED( to->type ) ) {
275 maxType = VT_SIGN( maxType );
276 }
277 // In this version, the step is not given - by default, step = 1
278 stepResident = variable_resident( _environment, maxType, "(step 1)" );
279 variable_store( _environment, stepResident->name, 1 );
280 }
281
282 loop->stepResident = stepResident;
283 loop->stepResident->locked = 1;
284
285 cpu_return( _environment );
286
287}
288
289void begin_for_identifier( Environment * _environment, char * _index ) {
290
291 Loop * loop = _environment->loops;
292
293 unsigned char beginForPrepareAfter[MAX_TEMPORARY_STORAGE]; sprintf(beginForPrepareAfter, "%sprepa", loop->label );
294 unsigned char beginForFromPrepare[MAX_TEMPORARY_STORAGE]; sprintf(beginForFromPrepare, "%sprepfrom", loop->label );
295 unsigned char beginForToPrepare[MAX_TEMPORARY_STORAGE]; sprintf(beginForToPrepare, "%sprepto", loop->label );
296 unsigned char beginForStepPrepare[MAX_TEMPORARY_STORAGE]; sprintf(beginForStepPrepare, "%sprepstep", loop->label );
297
298 cpu_label( _environment, beginForPrepareAfter );
299
300 cpu_call( _environment, beginForFromPrepare );
301 cpu_call( _environment, beginForToPrepare );
302 cpu_call( _environment, beginForStepPrepare );
303
304 Variable * index = NULL;
305 if ( variable_exists( _environment, _index ) ) {
306 index = variable_retrieve( _environment, _index );
307 } else {
308 if ( _environment->optionExplicit ) {
310 }
311 index = variable_retrieve_or_define( _environment, _index, _environment->defaultVariableType, 0 );
312 }
313
314 Variable * from = loop->fromResident;
315 Variable * to = loop->toResident;
316 Variable * step = loop->stepResident;
317
318 unsigned char beginFor[MAX_TEMPORARY_STORAGE]; sprintf(beginFor, "%sbf", loop->label );
319 unsigned char backwardFor[MAX_TEMPORARY_STORAGE]; sprintf(backwardFor, "%sback", loop->label );
320 unsigned char forwardFor[MAX_TEMPORARY_STORAGE]; sprintf(forwardFor, "%sforw", loop->label );
321 unsigned char continueFor[MAX_TEMPORARY_STORAGE]; sprintf(continueFor, "%scont", loop->label );
322 unsigned char endFor[MAX_TEMPORARY_STORAGE]; sprintf(endFor, "%sbis", loop->label );
323
324 Variable * isLastStep;
325
326 variable_move( _environment, loop->fromResident->name, index->name );
327
328 cpu_label( _environment, beginFor );
329
330 if ( !loop->step || loop->step->initializedByConstant ) {
331
332 if ( !loop->step || loop->step->value > 0 ) {
333
334 if ( loop->from->initializedByConstant ) {
335
336 if ( !check_datatype_limits( index->type, loop->from->value ) ) {
337 CRITICAL_FOR_OUTSIDE_LIMITS( index->name, loop->from->value );
338 }
339
340 // Finish the loop if the index is less than lower bound.
341 isLastStep = variable_less_than_const( _environment, index->name, loop->from->value, 0 );
342 cpu_bvneq( _environment, isLastStep->realName, endFor );
343 } else {
344 // Finish the loop if the index is less than lower bound.
345 isLastStep = variable_less_than( _environment, index->name, loop->fromResident->name, 0 );
346 cpu_bvneq( _environment, isLastStep->realName, endFor );
347 }
348
349 if ( loop->to->initializedByConstant ) {
350
351 if ( !check_datatype_limits( index->type, loop->to->value ) ) {
352 CRITICAL_FOR_OUTSIDE_LIMITS( index->name, loop->to->value );
353 }
354
355 // Finish the loop if the index is less than upper bound.
356 isLastStep = variable_greater_than_const( _environment, index->name, loop->to->value, 0 );
357 cpu_bvneq( _environment, isLastStep->realName, endFor );
358 } else {
359 // Finish the loop if the index is less than upper bound.
360 isLastStep = variable_greater_than( _environment, index->name, loop->toResident->name, 0 );
361 cpu_bvneq( _environment, isLastStep->realName, endFor );
362 }
363
364 } else if ( loop->step->value < 0 ) {
365
366 // Finish the loop if the index is less than lower bound.
367 if ( loop->from->initializedByConstant ) {
368
369 if ( !check_datatype_limits( index->type, loop->from->value ) ) {
370 CRITICAL_FOR_OUTSIDE_LIMITS( index->name, loop->from->value );
371 }
372
373 isLastStep = variable_greater_than_const( _environment, index->name, loop->from->value, 0 );
374 cpu_bvneq( _environment, isLastStep->realName, endFor );
375 } else {
376 isLastStep = variable_greater_than( _environment, index->name, loop->fromResident->name, 0 );
377 cpu_bvneq( _environment, isLastStep->realName, endFor );
378 }
379
380 // Finish the loop if the index is less than upper bound.
381 if ( loop->to->initializedByConstant ) {
382
383 if ( !check_datatype_limits( index->type, loop->to->value ) ) {
384 CRITICAL_FOR_OUTSIDE_LIMITS( index->name, loop->to->value );
385 }
386
387 isLastStep = variable_less_than_const( _environment, index->name, loop->to->value, 0 );
388 cpu_bvneq( _environment, isLastStep->realName, endFor );
389 } else {
390 isLastStep = variable_less_than( _environment, index->name, loop->toResident->name, 0 );
391 cpu_bvneq( _environment, isLastStep->realName, endFor );
392 }
393
394 } else {
395
396 cpu_jump( _environment, endFor );
397
398 }
399
400 } else {
401
402 cpu_bvneq( _environment, variable_greater_than_const( _environment, loop->stepResident->name, 0, 0)->realName, forwardFor );
403
404 cpu_jump( _environment, backwardFor );
405
406 cpu_label( _environment, forwardFor );
407
408 // Finish the loop if the index is less than lower bound.
409 isLastStep = variable_less_than( _environment, index->name, loop->fromResident->name, 0 );
410 cpu_bvneq( _environment, isLastStep->realName, endFor );
411
412 // Finish the loop if the index is less than upper bound.
413 isLastStep = variable_greater_than( _environment, index->name, loop->toResident->name, 0 );
414 cpu_bvneq( _environment, isLastStep->realName, endFor );
415
416 cpu_jump( _environment, continueFor );
417
418 cpu_label( _environment, backwardFor );
419
420 // Finish the loop if the index is less than lower bound.
421 isLastStep = variable_greater_than( _environment, index->name, loop->fromResident->name, 0 );
422 cpu_bvneq( _environment, isLastStep->realName, endFor );
423
424 // Finish the loop if the index is less than upper bound.
425 isLastStep = variable_less_than( _environment, index->name, loop->toResident->name, 0 );
426 cpu_bvneq( _environment, isLastStep->realName, endFor );
427
428 }
429
430 cpu_label( _environment, continueFor );
431
432 loop->index = index;
433
434}
435
436void begin_for( Environment * _environment, char * _index, char * _from, char * _to ) {
437
438 Variable * index = NULL;
439
440 Variable * from = variable_retrieve( _environment, _from );
441 Variable * to = variable_retrieve( _environment, _to );
442
443 int maxType = VT_MAX_BITWIDTH_TYPE( from->type, to->type );
444
445 if ( VT_SIGNED( from->type ) || VT_SIGNED( to->type ) ) {
446 maxType = VT_SIGN( maxType );
447 }
448
449 Variable * step = variable_resident( _environment, maxType, "(step 1)" );
450
451 if ( variable_exists( _environment, _index ) ) {
452 index = variable_retrieve( _environment, _index );
453 } else {
454 if ( _environment->optionExplicit ) {
456 }
457 index = variable_retrieve_or_define( _environment, _index, maxType, 0 );
458 }
459
460 Variable * toResident = variable_resident( _environment, index->type, "(resident to)" );
461 variable_move( _environment, to->name, toResident->name );
462
463 variable_store( _environment, step->name, 1 );
464
466
467 Loop * loop = malloc( sizeof( Loop ) );
468 memset( loop, 0, sizeof( Loop ) );
469 loop->label = strdup( label );
470 loop->type = LT_FOR;
471 loop->next = _environment->loops;
472 loop->index = index;
473 loop->from = from;
474 loop->from->locked = 1;
475 loop->fromResident = from;
476 loop->fromResident->locked = 1;
477 loop->to = to;
478 loop->to->locked = 1;
479 loop->toResident = to;
480 loop->toResident->locked = 1;
481 if ( step ) {
482 loop->step = step;
483 loop->step->locked = 1;
484 }
485 loop->stepResident = step;
486 loop->stepResident->locked = 1;
487 loop->statical = 1;
488 _environment->loops = loop;
489
490 variable_move( _environment, from->name, index->name );
491
492 unsigned char beginFor[MAX_TEMPORARY_STORAGE]; sprintf(beginFor, "%sbf", loop->label );
493 unsigned char endFor[MAX_TEMPORARY_STORAGE]; sprintf(endFor, "%sbis", loop->label );
494
495 cpu_label( _environment, beginFor );
496
497 Variable * isLastStep = variable_greater_than( _environment, index->name, loop->to->name, 0 );
498
499 cpu_bvneq( _environment, isLastStep->realName, endFor );
500
501}
void cpu_label(Environment *_environment, char *_label)
Definition 6309.c:356
void cpu_call(Environment *_environment, char *_label)
Definition 6309.c:3755
void cpu_jump(Environment *_environment, char *_label)
Definition 6309.c:3739
void cpu_bvneq(Environment *_environment, char *_value, char *_label)
Definition 6309.c:345
void cpu_return(Environment *_environment)
Definition 6309.c:4030
Variable * variable_retrieve(Environment *_environment, char *_name)
Variable * variable_less_than_const(Environment *_environment, char *_source, int _destination, int _equal)
Variable * variable_retrieve_or_define(Environment *_environment, char *_name, VariableType _type, int _value)
int variable_exists(Environment *_environment, char *_name)
Variable * variable_less_than(Environment *_environment, char *_source, char *_destination, int _equal)
Compare two variable and return the result of comparation.
Variable * variable_greater_than(Environment *_environment, char *_source, char *_destination, int _equal)
Compare two variable and return the result of comparation.
Variable * variable_move(Environment *_environment, char *_source, char *_destination)
Store the value of a variable inside another variable by converting it.
Variable * variable_resident(Environment *_environment, VariableType _type, char *_meaning)
Variable * variable_store(Environment *_environment, char *_destination, unsigned int _value)
Store a direct value to a variable.
Variable * variable_greater_than_const(Environment *_environment, char *_source, int _destination, int _equal)
int check_datatype_limits(VariableType _type, int _value)
void begin_for_identifier(Environment *_environment, char *_index)
Definition begin_for.c:289
void begin_for_from_prepare(Environment *_environment)
Definition begin_for.c:172
void begin_for_prepare(Environment *_environment, char *_index)
Emit ASM code for FOR ....
Definition begin_for.c:143
void begin_for(Environment *_environment, char *_index, char *_from, char *_to)
Definition begin_for.c:436
void begin_for_from_assign(Environment *_environment, char *_from)
Definition begin_for.c:182
void begin_for_step_assign(Environment *_environment, char *_step)
Definition begin_for.c:247
void begin_for_to_prepare(Environment *_environment)
Definition begin_for.c:206
void begin_for_step_prepare(Environment *_environment)
Definition begin_for.c:237
void begin_for_to_assign(Environment *_environment, char *_to)
Definition begin_for.c:216
VariableType defaultVariableType
Definition ugbc.h:2956
int optionExplicit
Definition ugbc.h:2457
Loop * loops
Definition ugbc.h:2669
char * name
Definition ugbc.h:979
VariableType type
Definition ugbc.h:988
int value
Definition ugbc.h:1025
int initializedByConstant
Definition ugbc.h:1036
char * realName
Definition ugbc.h:982
void * malloc(YYSIZE_T)
#define CRITICAL_FOR_OUTSIDE_LIMITS(v, a)
Definition ugbc.h:3811
#define MAX_TEMPORARY_STORAGE
Definition ugbc.h:563
void loop(Environment *_environment, char *_label)
#define VT_SIGNED(t)
Definition ugbc.h:618
#define CRITICAL_VARIABLE_UNDEFINED(f)
Definition ugbc.h:3602
struct _Variable Variable
Structure of a single variable.
struct _Environment Environment
Structure of compilation environment.
@ LT_FOR
Definition ugbc.h:1396
#define VT_MAX_BITWIDTH_TYPE(a, b)
Definition ugbc.h:606
struct _Loop Loop
Structure of a single loop.
#define VT_SIGN(t)
Definition ugbc.h:633
#define MAKE_LABEL
Definition ugbc.h:3351