ugBASIC 1.18
An isomorphic BASIC language compiler for retrocomputers
Loading...
Searching...
No Matches
data.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#include <math.h>
37
38/****************************************************************************
39 * CODE SECTION
40 ****************************************************************************/
41
48 /* <usermanual>
49@keyword DATA
50
51@english
52
53The ''DATA'' command is used to create a list of data that will be used
54in other parts of the program. It is like a container where values are
55stored that will then be "read" and used by other commands.
56
57The ''DATA'' command is usually placed at the beginning of the program or in
58a section dedicated to the definitions of data, but it is not mandatory.
59The ''data1'', ''data2'', ... so on should be replaced with the data you want to
60store inside the program. These can be numbers or text strings. To read the
61data contained in a ''DATA'' statement, you use the ''READ'' command.
62This command assigns the values contained in ''DATA'' to variables.
63
64You can use multiple ''DATA'' statements to fill an array with a set of values.
65Another usage is to create small tables of data, for example to represent
66menus or product lists. You can also store constants that are used frequently
67in the program.
68
69The ''DATA'' values will be read from left to right, beginning with the first
70line containing a ''DATA'' statement. Each time a ''READ'' instruction is
71executed the saved ''DATA'' position of the last ''READ'' is advanced to the
72next value. Strings must be written in quotes, so characters
73like comma, space, colon, graphical ones or control characters has to be
74written inside double quotes like string constants. The ''RESTORE'' resets
75the pointer of the current ''DATA'' position the program start so that
76next ''READ'' will read from the first ''DATA'' found from the beginning
77of the program.
78
79The instruction ''DATA'' stores numeric data in an optimized way: so, if you enter a numeric
80constant that can be represented by a single byte, it will be stored in the program
81as a single byte. Floating point numbers are stored with default precision.
82Finally, strings are stored "as is". As a result, when you use the ''READ'' command,
83ugBASIC will implicitly perform the conversion if the same data type is not used,
84and if it is posssible. It is possible to avoid this behavious by using the ''AS''
85keyword, followed by the data type.
86
87Separates the definition of data from its use, makes the code more readable
88and maintainable. You can change the data without having to change the
89logic of the program. Finally, the same data can be read multiple times
90in different parts of the program.
91
92There is also a version of the syntax that allows you to load values from
93an external file. This syntax is currently limited to numeric data that must be
94separated by a non-numeric separator.
95
96@italian
97
98Il comando ''DATA'' serve per creare un elenco di dati che saranno
99utilizzati in altre parti del programma. È come un contenitore in
100cui vengono memorizzati valori che saranno poi "letti" e utilizzati
101da altri comandi.
102
103Il comando ''DATA'' è solitamente posizionato all'inizio del programma
104o in una sezione dedicata alle definizioni dei dati, ma non è obbligatorio.
105''data1'', ''data2'', ... e così via devono essere sostituiti con i dati che si
106desidera memorizzare all'interno del programma. Possono essere numeri o
107stringhe di testo. Per leggere i dati contenuti in un'istruzione ''DATA'',
108si utilizza il comando ''READ''. Questo comando assegna i valori contenuti
109in ''DATA'' alle variabili.
110
111È possibile utilizzare più istruzioni ''DATA'' per riempire un array con
112un set di valori. Un altro utilizzo è quello di creare piccole tabelle di
113dati, ad esempio per rappresentare menu o elenchi di prodotti. È inoltre
114possibile memorizzare costanti che vengono utilizzate frequentemente nel
115programma.
116
117I valori ''DATA'' verranno letti da sinistra a destra, iniziando dalla
118prima riga contenente un'istruzione ''DATA''. Ogni volta che viene eseguita
119un'istruzione ''READ'', la posizione ''DATA'' salvata dell'ultimo ''READ''
120viene avanzata al valore successivo. Le stringhe devono essere scritte
121tra virgolette, quindi caratteri come virgola, spazio, due punti,
122caratteri grafici o caratteri di controllo devono essere scritti tra
123virgolette doppie come le costanti stringa. ''RESTORE'' reimposta il
124puntatore della posizione ''DATA'' corrente all'avvio del programma
125in modo che il successivo ''READ'' legga dal primo ''DATA'' trovato
126dall'inizio del programma.
127
128L'istruzione ''DATA'' memorizza i dati numerici in modo ottimizzato:
129quindi, se si immette una costante numerica che può essere rappresentata
130da un singolo byte, verrà memorizzata nel programma come un singolo byte.
131I numeri in virgola mobile vengono memorizzati con precisione predefinita.
132Infine, le stringhe vengono memorizzate "così come sono". Di conseguenza,
133quando si usa il comando ''READ'', ugBASIC eseguirà implicitamente la
134conversione se non viene usato lo stesso tipo di dati e se è possibile.
135È possibile evitare questo comportamento usando la parola chiave ''AS'',
136seguita dal tipo di dati.
137
138Separa la definizione dei dati dal loro utilizzo, rende il codice più
139leggibile e gestibile. È possibile modificare i dati senza dover cambiare
140la logica del programma. Infine, gli stessi dati possono essere letti
141più volte in diverse parti del programma.
142
143E' disponibile anche una versione della sintassi che permette di caricare
144i valori presenti in un file esterno. Questa sintassi, al momento, è
145limitata ai dati di tipo numerico che devono essere separati da un
146separatore non numerico.
147
148@syntax DATA data1 [, data2 [, data3 ... ] ]
149@syntaxDATA [AS data type] data1 [, data2 [, data3 ... ] ]
150@syntaxDATA LOAD "filename" AS TEXT
151
152@example DATA 10, 20, "test"
153@example DATA AS INTEGER 10, 20, 30
154@example DATA LOAD "datas.txt" AS TEXT
155
156@usedInExample data_example_01.bas
157@usedInExample data_example_02.bas
158@usedInExample data_example_03.bas
159@usedInExample data_example_05.bas
160
161</usermanual> */
162void data_numeric( Environment * _environment, int _value ) {
163
164 VariableType type;
165
166 if ( _environment->dataDataType ) {
167 type = _environment->dataDataType;
168 } else {
169 type = variable_type_from_numeric_value( _environment, _value );
170 }
171
172 int bytes = VT_BITWIDTH( type ) >> 3;
173
174 DataSegment * data;
175
176 if ( _environment->lastDefinedLabel ) {
177 if ( _environment->lastDefinedLabelIsNumeric ) {
178 data = data_segment_define_or_retrieve_numeric( _environment, _environment->lastDefinedLabelNumeric );
179 } else {
180 data = data_segment_define_or_retrieve( _environment, _environment->lastDefinedLabel );
181 }
182 } else {
183 data = data_segment_define_or_retrieve( _environment, "DATA" );
184 }
185
186 DataDataSegment * dataDataSegment = malloc( sizeof( DataDataSegment ) );
187 memset( dataDataSegment, 0, sizeof( DataDataSegment ) );
188 dataDataSegment->size = bytes;
189 dataDataSegment->data = malloc( bytes );
190 dataDataSegment->type = type;
191 dataDataSegment->absoluteAddress = _environment->dataLastAbsoluteAddress;
192 _environment->dataLastAbsoluteAddress += bytes;
193#if defined(CPU_BIG_ENDIAN)
194 char * value = (char *)&_value;
195 for( int i=0; i<bytes; ++i ) {
196 dataDataSegment->data[bytes-i-1] = value[i];
197 }
198#else
199 memcpy( dataDataSegment->data, &_value, bytes );
200#endif
201
202 DataDataSegment * final = data->data;
203
204 if ( final ) {
205 while( final->next ) {
206 final = final->next;
207 }
208 final->next = dataDataSegment;
209 } else {
210 data->data = dataDataSegment;
211 }
212
213 if ( _environment->dataDataType ) {
214 data->type = _environment->dataDataType;
215 }
216
217}
218
225void data_floating( Environment * _environment, double _value ) {
226
227 VariableType type = VT_FLOAT;
228
229 int bytes = VT_FLOAT_BITWIDTH( _environment->floatType.precision ) >> 3;
230
231 DataSegment * data;
232
233 if ( _environment->lastDefinedLabel ) {
234 if ( _environment->lastDefinedLabelIsNumeric ) {
235 data = data_segment_define_or_retrieve_numeric( _environment, _environment->lastDefinedLabelNumeric );
236 } else {
237 data = data_segment_define_or_retrieve( _environment, _environment->lastDefinedLabel );
238 }
239 } else {
240 data = data_segment_define_or_retrieve( _environment, "DATA" );
241 }
242
243 int result[32];
244 cpu_float_single_from_double_to_int_array( _environment, _value, result );
245
246 DataDataSegment * dataDataSegment = malloc( sizeof( DataDataSegment ) );
247 memset( dataDataSegment, 0, sizeof( DataDataSegment ) );
248 dataDataSegment->size = bytes;
249 dataDataSegment->data = malloc( bytes );
250 dataDataSegment->type = type;
251 dataDataSegment->precision = _environment->floatType.precision;
252 dataDataSegment->absoluteAddress = _environment->dataLastAbsoluteAddress;
253 _environment->dataLastAbsoluteAddress += bytes;
254 for( int i=0; i<bytes; ++i ) {
255 dataDataSegment->data[i] = (char)(result[i] & 0xff );
256 }
257
258 DataDataSegment * final = data->data;
259
260 if ( final ) {
261 while( final->next ) {
262 final = final->next;
263 }
264 final->next = dataDataSegment;
265 } else {
266 data->data = dataDataSegment;
267 }
268
269 if ( _environment->dataDataType ) {
270 data->type = _environment->dataDataType;
271 }
272
273}
274
281void data_string( Environment * _environment, char * _value ) {
282
283 VariableType type = VT_STRING;
284
285 int bytes;
286
287 char * value = unescape_string( _environment, _value, 0, &bytes );
288
289 DataSegment * data;
290
291 if ( _environment->lastDefinedLabel ) {
292 if ( _environment->lastDefinedLabelIsNumeric ) {
293 data = data_segment_define_or_retrieve_numeric( _environment, _environment->lastDefinedLabelNumeric );
294 } else {
295 data = data_segment_define_or_retrieve( _environment, _environment->lastDefinedLabel );
296 }
297 } else {
298 data = data_segment_define_or_retrieve( _environment, "DATA" );
299 }
300
301 DataDataSegment * dataDataSegment = malloc( sizeof( DataDataSegment ) );
302 memset( dataDataSegment, 0, sizeof( DataDataSegment ) );
303 dataDataSegment->size = bytes;
304 dataDataSegment->data = malloc( bytes + 1 );
305 memset( dataDataSegment->data, 0, bytes + 1 );
306 dataDataSegment->type = type;
307 memcpy( dataDataSegment->data, value, bytes );
308 dataDataSegment->absoluteAddress = _environment->dataLastAbsoluteAddress;
309 _environment->dataLastAbsoluteAddress += bytes;
310
311 if ( _environment->dataDataType ) {
312 data->type = _environment->dataDataType;
313 }
314
315 DataDataSegment * final = data->data;
316
317 if ( final ) {
318 while( final->next ) {
319 final = final->next;
320 }
321 final->next = dataDataSegment;
322 } else {
323 data->data = dataDataSegment;
324 }
325
326}
327
328void data_type( Environment * _environment ) {
329
330 VariableType type;
331
332 DataSegment * data;
333
334 int os = VT_OPTIMAL_SHIFT( _environment->currentType->size );
335 int bytes = 1 << os;
336
337 if ( _environment->lastDefinedLabel ) {
338 if ( _environment->lastDefinedLabelIsNumeric ) {
339 data = data_segment_define_or_retrieve_numeric( _environment, _environment->lastDefinedLabelNumeric );
340 } else {
341 data = data_segment_define_or_retrieve( _environment, _environment->lastDefinedLabel );
342 }
343 } else {
344 data = data_segment_define_or_retrieve( _environment, "DATA" );
345 }
346
347 DataDataSegment * dataDataSegment = malloc( sizeof( DataDataSegment ) );
348 memset( dataDataSegment, 0, sizeof( DataDataSegment ) );
349 dataDataSegment->size = bytes;
350 dataDataSegment->data = malloc( bytes );
351 memset( dataDataSegment->data, 0, bytes );
352 dataDataSegment->type = VT_TYPE;
353 dataDataSegment->absoluteAddress = _environment->dataLastAbsoluteAddress;
354 _environment->dataLastAbsoluteAddress += bytes;
355 Constant * current = _environment->currentFieldsValues;
356 Field * currentField = _environment->currentType->first;
357 int offset = 0;
358 while( current ) {
359 switch( VT_BITWIDTH( currentField->type ) ) {
360 case 8:
361 dataDataSegment->data[offset] = (unsigned char)current->value & 0xff;
362 ++offset;
363 break;
364 case 16:
365#if defined(CPU_BIG_ENDIAN)
366 dataDataSegment->data[offset+1] = (unsigned char)current->value & 0xff;
367 dataDataSegment->data[offset] = (unsigned char)((current->value>>8) & 0xff);
368#else
369 dataDataSegment->data[offset] = (unsigned char)current->value & 0xff;
370 dataDataSegment->data[offset+1] = (unsigned char)((current->value>>8) & 0xff);
371#endif
372 offset+=2;
373 break;
374 case 32:
375#if defined(CPU_BIG_ENDIAN)
376 dataDataSegment->data[offset+3] = (unsigned char)current->value & 0xff;
377 dataDataSegment->data[offset+2] = (unsigned char)((current->value>>8) & 0xff);
378 dataDataSegment->data[offset+1] = (unsigned char)((current->value>>16) & 0xff);
379 dataDataSegment->data[offset] = (unsigned char)((current->value>>24) & 0xff);
380#else
381 dataDataSegment->data[offset] = (unsigned char)current->value & 0xff;
382 dataDataSegment->data[offset+1] = (unsigned char)((current->value>>8) & 0xff);
383 dataDataSegment->data[offset+2] = (unsigned char)((current->value>>16) & 0xff);
384 dataDataSegment->data[offset+3] = (unsigned char)((current->value>>24) & 0xff);
385#endif
386 offset+=4;
387 break;
388 }
389 current = current->next;
390 currentField = currentField->next;
391 }
392
393 DataDataSegment * final = data->data;
394
395 if ( final ) {
396 while( final->next ) {
397 final = final->next;
398 }
399 final->next = dataDataSegment;
400 } else {
401 data->data = dataDataSegment;
402 }
403
404 data->type = VT_TYPE;
405
406}
void cpu_float_single_from_double_to_int_array(Environment *_environment, double _value, int _result[])
Definition 6309.c:6747
#define VT_FLOAT_BITWIDTH(p)
Definition 6309.h:38
DataSegment * data_segment_define_or_retrieve_numeric(Environment *_environment, int _number)
VariableType variable_type_from_numeric_value(Environment *_environment, int _number)
DataSegment * data_segment_define_or_retrieve(Environment *_environment, char *_name)
char * unescape_string(Environment *_environment, char *_value, int _printing, int *_final_size)
int offset
Definition _optimizer.c:681
void data_string(Environment *_environment, char *_value)
Emit code for DATA instruction (string values).
Definition data.c:281
void data_type(Environment *_environment)
Definition data.c:328
void data_floating(Environment *_environment, double _value)
Emit code for DATA instruction (float values).
Definition data.c:225
void data_numeric(Environment *_environment, int _value)
Emit code for DATA instruction (numeric values).
Definition data.c:162
int value
Definition ugbc.h:815
struct _Constant * next
Definition ugbc.h:832
FloatTypePrecision precision
Definition ugbc.h:2176
int absoluteAddress
Definition ugbc.h:2177
char * data
Definition ugbc.h:2178
VariableType type
Definition ugbc.h:2175
int lastDefinedLabelIsNumeric
Definition ugbc.h:2590
Constant * currentFieldsValues
Definition ugbc.h:3265
int lastDefinedLabelNumeric
Definition ugbc.h:2585
FloatType floatType
Definition ugbc.h:2400
Type * currentType
Definition ugbc.h:2540
int dataLastAbsoluteAddress
Definition ugbc.h:3278
VariableType dataDataType
Definition ugbc.h:2850
char * lastDefinedLabel
Definition ugbc.h:2583
VariableType type
Definition ugbc.h:1233
struct _Field * next
Definition ugbc.h:1237
FloatTypePrecision precision
Definition ugbc.h:868
int size
Definition ugbc.h:1245
struct _Field * first
Definition ugbc.h:1247
void * malloc(YYSIZE_T)
struct _Field Field
#define VT_OPTIMAL_SHIFT(s)
Definition ugbc.h:604
struct _Environment Environment
Structure of compilation environment.
@ VT_FLOAT
Definition ugbc.h:522
@ VT_STRING
Definition ugbc.h:474
@ VT_TYPE
Definition ugbc.h:546
struct _Constant Constant
Structure of a single constant.
struct _DataDataSegment DataDataSegment
enum _VariableType VariableType
Type of variables.
struct _DataSegment DataSegment
#define VT_BITWIDTH(t)
Definition ugbc.h:595