DATAGEN is a utility that generates a DATA statement in memory by directly POKEing bytes into the BASIC program area. It prompts the user for the desired number of bytes and a target line number, then calculates available space within the existing REM-filled program structure to house the new DATA line. The program navigates the BASIC line-length bytes stored in the program area to locate a suitable address, writes the line number, length, and DATA keyword token byte (228) directly, and fills in quoted string entries as the user inputs them one at a time. After entry is complete, it can optionally delete itself while leaving the generated DATA line intact, making it useful as a self-removing code-generation tool.
Program Structure
The program is divided into two distinct regions. Lines 1 through 493 consist entirely of empty REM statements, which serve as a large contiguous block of pre-allocated program space. This space is reserved so that a new DATA line can be constructed inside it at runtime. The active logic begins at line 9972 and runs through 9999.
Purpose of the REM Block
The 493 consecutive empty REM lines are not decorative — they are the raw material. The BASIC interpreter stores each line as a header (line number, 2 bytes; length, 2 bytes) followed by a token byte and a newline. By scanning the program area with PEEK, the code locates the first REM-region address that provides enough contiguous space to hold n bytes of DATA content. The REM lines thus act as a pool of reserved memory that the utility carves a DATA line out of.
Key Variables
| Variable | Purpose |
|---|---|
n | Number of bytes requested for the DATA statement |
l | Target BASIC line number for the new DATA line (must be < 9997) |
prog | Start address of the BASIC program, read from system variables at addresses 23635–23636 |
adr | Crawling pointer used to walk the BASIC line-length chain |
ad | Final address marking the end of the available space block |
bytes | Actual byte count available for the DATA line content |
d$ | Each string entry typed by the user |
z | Loop counter for POKEing individual characters |
Memory Navigation Technique
Lines 9978–9982 implement a walk through the BASIC program’s line-length chain. The system variable pair at addresses 23635–23636 gives the start of the BASIC program. From there, each line’s length is stored as a little-endian 16-bit word at offsets +2 and +3 from the line start (offset +3 is the low byte and +4 the high byte as used here, accounting for the 2-byte line number preceding the length). The loop at line 9980 advances adr by 4 + PEEK(adr+3) + 256*PEEK(adr+4) until it finds a position where prog+5+n < adr, meaning the preceding block is large enough to hold the new DATA line.
Direct POKE Construction of a BASIC Line
Once the target address is found, the program constructs a valid BASIC line entirely through POKE operations:
- Line
9983: POKEs the high and low bytes of the new line number (l) intoprogandprog+1. - Line
9984: Calculates the line body length (bytes = ad - prog - 3) and writes it as a little-endian word toprog+2andprog+3. - Line
9985: POKEs token byte228(theDATAkeyword) atprog+4. - Lines
9988–9993: Each user-entered string is surrounded by quote characters (ASCII 34) and followed by a comma (ASCII 44), written byte-by-byte with POKE.
User Interaction Loop
Lines 9988–9993 form the data-entry loop. Each iteration opens a quoted string slot (POKE 34), reads d$ via INPUT, checks whether the entry fits in the remaining space, POKEs each character individually with a FOR/NEXT loop, then writes closing quote (34) and comma (44). Entering end or END exits the loop. A BEEP pair signals each prompt.
Self-Deletion Mechanism
After the DATA line is built, line 9995 prompts the user to press D to delete the DATAGEN program itself. Lines 9997 and 9998 use a pair of bare numeric arguments — a known technique where a line beginning with just a number causes the interpreter to delete the line with that number — to remove lines 9996 and 9997 from the program. Meanwhile, the new DATA line at its user-chosen line number (less than 9997) remains intact, effectively leaving only the DATA statement behind.
Notable Idioms and Techniques
- Reading PROG from system variables:
PEEK 23635 + 256 * PEEK 23636— standard Spectrum system variable access. POKE 23561,200andPOKE 23609,100at line9976adjust the editor margin and RAMTOP-related settings to give INPUT more display room.- The boundary check
IF NOT (l<9997)at line9977ensures the new line number does not collide with the utility’s own line range. - Line
9994fills unused space at the end of the allocated block with spaces (ASCII 32) to sanitize leftover REM data. - The fit check at line
9990—adr + LEN d$ + 4 > ad— prevents overwriting memory beyond the reserved block.
Bugs and Anomalies
The line-length byte-order used in lines 9980 and 9984 treats offset +3 as the low byte and +4 as the high byte of the length word, which is consistent with the TS2068 BASIC line format (line number high, line number low, length low, length high — noting the 1-based offset from the line start as the pointer is decremented by 1 at line 9979). The arithmetic is internally consistent though non-obvious without careful tracing. The final DATA line will contain a trailing comma after the last entry because the comma is written unconditionally in line 9992 before the loop checks for end; this trailing comma after the last quoted value could cause a syntax issue depending on how the DATA line is later consumed.
Source Code
1 REM
2 REM
3 REM
4 REM
5 REM
6 REM
7 REM
8 REM
9 REM
10 REM
11 REM
12 REM
13 REM
14 REM
15 REM
16 REM
17 REM
18 REM
19 REM
20 REM
21 REM
22 REM
23 REM
24 REM
25 REM
26 REM
27 REM
28 REM
29 REM
30 REM
31 REM
32 REM
33 REM
34 REM
35 REM
36 REM
37 REM
38 REM
39 REM
40 REM
41 REM
42 REM
43 REM
44 REM
45 REM
46 REM
47 REM
48 REM
49 REM
50 REM
51 REM
52 REM
53 REM
54 REM
55 REM
56 REM
57 REM
58 REM
59 REM
60 REM
61 REM
62 REM
63 REM
64 REM
65 REM
66 REM
67 REM
68 REM
69 REM
70 REM
71 REM
72 REM
73 REM
74 REM
75 REM
76 REM
77 REM
78 REM
79 REM
80 REM
81 REM
82 REM
83 REM
84 REM
85 REM
86 REM
87 REM
88 REM
89 REM
90 REM
91 REM
92 REM
93 REM
94 REM
95 REM
96 REM
97 REM
98 REM
99 REM
100 REM
101 REM
102 REM
103 REM
104 REM
105 REM
106 REM
107 REM
108 REM
109 REM
110 REM
111 REM
112 REM
113 REM
114 REM
115 REM
116 REM
117 REM
118 REM
119 REM
120 REM
121 REM
122 REM
123 REM
124 REM
125 REM
126 REM
127 REM
128 REM
129 REM
130 REM
131 REM
132 REM
133 REM
134 REM
135 REM
136 REM
137 REM
138 REM
139 REM
140 REM
141 REM
142 REM
143 REM
144 REM
145 REM
146 REM
147 REM
148 REM
149 REM
150 REM
151 REM
152 REM
153 REM
154 REM
155 REM
156 REM
157 REM
158 REM
159 REM
160 REM
161 REM
162 REM
163 REM
164 REM
165 REM
166 REM
167 REM
168 REM
169 REM
170 REM
171 REM
172 REM
173 REM
174 REM
175 REM
176 REM
177 REM
178 REM
179 REM
180 REM
181 REM
182 REM
183 REM
184 REM
185 REM
186 REM
187 REM
188 REM
189 REM
190 REM
191 REM
192 REM
193 REM
194 REM
195 REM
196 REM
197 REM
198 REM
199 REM
200 REM
201 REM
202 REM
203 REM
204 REM
205 REM
206 REM
207 REM
208 REM
209 REM
210 REM
211 REM
212 REM
213 REM
214 REM
215 REM
216 REM
217 REM
218 REM
219 REM
220 REM
221 REM
222 REM
223 REM
224 REM
225 REM
226 REM
227 REM
228 REM
229 REM
230 REM
231 REM
232 REM
233 REM
234 REM
235 REM
236 REM
237 REM
238 REM
239 REM
240 REM
241 REM
242 REM
243 REM
244 REM
245 REM
246 REM
247 REM
248 REM
249 REM
250 REM
251 REM
252 REM
253 REM
254 REM
255 REM
256 REM
257 REM
258 REM
259 REM
260 REM
261 REM
262 REM
263 REM
264 REM
265 REM
266 REM
267 REM
268 REM
269 REM
270 REM
271 REM
272 REM
273 REM
274 REM
275 REM
276 REM
277 REM
278 REM
279 REM
280 REM
281 REM
282 REM
283 REM
284 REM
285 REM
286 REM
287 REM
288 REM
289 REM
290 REM
291 REM
292 REM
293 REM
294 REM
295 REM
296 REM
297 REM
298 REM
299 REM
300 REM
301 REM
302 REM
303 REM
304 REM
305 REM
306 REM
307 REM
308 REM
309 REM
310 REM
311 REM
312 REM
313 REM
314 REM
315 REM
316 REM
317 REM
318 REM
319 REM
320 REM
321 REM
322 REM
323 REM
324 REM
325 REM
326 REM
327 REM
328 REM
329 REM
330 REM
331 REM
332 REM
333 REM
334 REM
335 REM
336 REM
337 REM
338 REM
339 REM
340 REM
341 REM
342 REM
343 REM
344 REM
345 REM
346 REM
347 REM
348 REM
349 REM
350 REM
351 REM
352 REM
353 REM
354 REM
355 REM
356 REM
357 REM
358 REM
359 REM
360 REM
361 REM
362 REM
363 REM
364 REM
365 REM
366 REM
367 REM
368 REM
369 REM
370 REM
371 REM
372 REM
373 REM
374 REM
375 REM
376 REM
377 REM
378 REM
379 REM
380 REM
381 REM
382 REM
383 REM
384 REM
385 REM
386 REM
387 REM
388 REM
389 REM
390 REM
391 REM
392 REM
393 REM
394 REM
395 REM
396 REM
397 REM
398 REM
399 REM
400 REM
401 REM
402 REM
403 REM
404 REM
405 REM
406 REM
407 REM
408 REM
409 REM
410 REM
411 REM
412 REM
413 REM
414 REM
415 REM
416 REM
417 REM
418 REM
419 REM
420 REM
421 REM
422 REM
423 REM
424 REM
425 REM
426 REM
427 REM
428 REM
429 REM
430 REM
431 REM
432 REM
433 REM
434 REM
435 REM
436 REM
437 REM
438 REM
439 REM
440 REM
441 REM
442 REM
443 REM
444 REM
445 REM
446 REM
447 REM
448 REM
449 REM
450 REM
451 REM
452 REM
453 REM
454 REM
455 REM
456 REM
457 REM
458 REM
459 REM
460 REM
461 REM
462 REM
463 REM
464 REM
465 REM
466 REM
467 REM
468 REM
469 REM
470 REM
471 REM
472 REM
473 REM
474 REM
475 REM
476 REM
477 REM
478 REM
479 REM
480 REM
481 REM
482 REM
483 REM
484 REM
485 REM
486 REM
487 REM
488 REM
489 REM
490 REM
491 REM
492 REM
493 REM
9972 REM FIRST:IF 4K is not enough spacethen the longest DATA line you need then EDIT 10 & change its line no. till you have enoughSECOND: MERGE this program
9974 REM GO TO 9999 TO SAVE all this THEN you can LOAD this or RUN LINE 9976
9976 CLS :POKE 23561,200:POKE 23609,100:INPUT "How many bytes do you need in the DATA statement? ";n
9977 INPUT "What will be the DATA statement LINE number (less then 9997) ";l:IF NOT (l<9997) THEN GO TO 9977
9978 PRINT AT 10,10;"Please wait":LET prog= PEEK 23635+256* PEEK 23636
9979 LET adr=prog-1
9980 LET adr=adr+4+ PEEK (adr+3)+256* PEEK (adr+4)
9981 IF prog+5+n<adr THEN LET ad=adr:GO TO 9983
9982 GO TO 9980
9983 POKE prog,0:POKE prog+1,1
9984 LET bytes=ad-prog-3:POKE prog+3, INT (bytes/256):POKE prog+2,bytes-256* INT (bytes/256)
9985 POKE prog+4,228
9986 CLS :PRINT "Enter DATA THEN press ENTER key after each entry."''"Enter the word ""end""to STOP the list"''"Number of bytes in DATA "'"list = ";bytes-3;'"(this includes quotes, commas,"'"and the word ""DATA "")."
9987 LET adr=prog+4
9988 LET adr=adr+1:POKE adr,34
9989 BEEP .02,1:BEEP .02,1:INPUT d$:IF d$="end" OR d$="END" THEN CLS :GO TO 9994
9990 IF adr+ LEN d$+4>ad THEN CLS :PRINT AT 5,0;"""";d$;""" does not fit in this"'"DATA list.":GO TO 9994
9991 FOR z=1 TO LEN d$:LET adr=adr+1:POKE adr, CODE d$(z):NEXT z
9992 LET adr=adr+1:POKE adr,34:LET adr=adr+1:POKE adr,44
9993 GO TO 9988
9994 PRINT AT 10,10;"Please Wait":FOR z=adr-1 TO ad-1:POKE z,32:NEXT z
9995 BEEP .5,5:BEEP .5,-5:BEEP .5,5:BEEP .5,-5:PRINT AT 15,0;"Depress Letter D to DELETE this program. The DATA list will notbe Deleted."
9996 IF INKEY$ <>"d" AND INKEY$ <>"D" THEN GO TO 9996
9997 2,9996:POKE prog, INT (l/256):POKE prog+1,l-256* INT (l/256):CLS
9998 9997,
9999 SAVE "DATAGEN" LINE 9976Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.