DATAGEN

Date: 198x
Type: Program
Platform(s): TS 2068
Tags: Utility

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

VariablePurpose
nNumber of bytes requested for the DATA statement
lTarget BASIC line number for the new DATA line (must be < 9997)
progStart address of the BASIC program, read from system variables at addresses 23635–23636
adrCrawling pointer used to walk the BASIC line-length chain
adFinal address marking the end of the available space block
bytesActual byte count available for the DATA line content
d$Each string entry typed by the user
zLoop counter for POKEing individual characters

Memory Navigation Technique

Lines 99789982 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:

  1. Line 9983: POKEs the high and low bytes of the new line number (l) into prog and prog+1.
  2. Line 9984: Calculates the line body length (bytes = ad - prog - 3) and writes it as a little-endian word to prog+2 and prog+3.
  3. Line 9985: POKEs token byte 228 (the DATA keyword) at prog+4.
  4. Lines 99889993: 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 99889993 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,200 and POKE 23609,100 at line 9976 adjust the editor margin and RAMTOP-related settings to give INPUT more display room.
  • The boundary check IF NOT (l<9997) at line 9977 ensures the new line number does not collide with the utility’s own line range.
  • Line 9994 fills unused space at the end of the allocated block with spaces (ASCII 32) to sanitize leftover REM data.
  • The fit check at line 9990adr + 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 9976

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.