THOREAU BASIC 3.2 ================= Homepage : https://thoreaubasic.com Itch site: https://tarjan.itch.io/thoreaubasic Mail : info@thoreaubasic.com A 64-bit BASIC interpreter for x64 Windows and x64 UEFI. Thoreau BASIC keeps the direct, line-numbered style of classic Microsoft BASIC, adds modern 64-bit memory and graphics, and can run either as a Windows program or directly from UEFI firmware without an operating system. Version 3.2 adds file and directory arrays, framed selection boxes, longer case-preserving paths, generic recovery and verified-copy commands, text statistics and expanded support diagnostics. RUN can restart a program without growing the host stack. Targeted JIT changes reduce scalar and hypercomplex overhead while retaining the existing numeric behavior. The 3.1 Opus wavetable and audio facilities remain available. MANDELZOOM.BAS is an interactive scalar Mandelbrot example with mouse panning and zooming. The following introductions and release sections retain the earlier history. In particular, 3.2 supersedes older uppercase directory-display and case-insensitive file-mask behavior. See FILES / DIRECTORIES for current rules. Version 3.1 adds six Opus-compressed wavetable choices and faster parallel loading, including a UEFI decoding fix confirmed working in VirtualBox. Every sample is expanded to PCM before playback; music never performs decompression. LOADWAV also accepts FLAC and Ogg Opus. CAPTURE collects diagnostic output, ERROR$ exposes error messages, and SOUNDGROUP maps instruments to their groups. Status confirmations are quiet in stored programs. LINE INPUT accepts either prompt separator, AUDIT warns about function-name conflicts, and ^ now evaluates left to right. PARFOR, graphics fills, strings and memory operations do less repeated work. Existing TBGM2/TBGM3 banks and audio slot commands remain usable. Version 3.0 makes sampled sound a first-class part of Thoreau BASIC. The public instrument engine is a General MIDI / GS wavetable backed by THOREAU_GM.TBGM, with programs 0..127, four drum kits at 128..131, the 47 standard GM percussion keys and 14 mapped GS extra percussion keys per kit. The same BASIC-facing instrument layout is used on Windows and UEFI. 3.0 also adds asynchronous WAV and Standard MIDI File playback, MIDI controller and GS handling, reverb/chorus/delay sends, live sound diagnostics and explicit SOUND PRELOAD support. TBGM3 banks are stored losslessly and can be decompressed by multiple workers at startup; the decoded PCM remains byte-identical to the stored source audio. The runtime receives four targeted efficiency passes as well. Registered ON ERROR, timer and mouse handlers can coexist with eligible native assignment/FOR/WHILE regions instead of automatically forcing those regions back to the interpreter. Sprite drawing can restore and recompose a bounded dirty rectangle instead of the whole framebuffer when the changed base area is known. The audio engine reuses exact derived exponential coefficients when their exact inputs have not changed. LOAD, MERGE and CHAIN defer repeated token/JIT/profile invalidation until the scoped source import finishes. Version 2.5.4 was an integer-JIT performance and legacy text/input compatibility release. The native engine keeps substantially more integer loop, scalar and one-dimensional array work on direct x64 paths, including quotient/remainder reuse for matching \ and MOD operations and affine FOR-indexed array stores. Windows raw keyboard input, VIEW PRINT/LOCATE coordinates and classic PRINT control characters were brought closer to GW-BASIC behaviour. Version 2.5.3.1 was a cumulative hotfix and native-execution update over 2.5.3. It fixed Windows CP437/Unicode clipboard and keyboard interoperability, VIEW border clipping, runaway recursive DEF FN calls and TRACE behaviour. It also further reduced JIT/PARFOR overhead in hot numeric code and made sampled PROFILE useful inside PARFOR workers. Version 2.5.3 is a compatibility, graphics-text, input and UEFI display update. It tightens several GW-BASIC parser and DATA/READ/RESTORE semantics, makes caught ON ERROR errors silent by default, fixes DEF FN typing and hypercomplex equality, adds exact-pixel GPRINT and cross-platform clipboard access, and improves error line attribution inside compiled JIT regions. On UEFI, version 2.5.3 also substantially reworks display presentation and input hot paths. Text/glyph output and bulk framebuffer operations are faster, cached backbuffer/GOP-BLT presentation can keep machines responsive when direct GOP writes are slow, long-running graphics present progressively, and keyboard/mouse polling avoids several unnecessary firmware calls and pointer repaints. On x64 UEFI, PARFOR now uses a persistent worker pool for the duration of a running BASIC program. Application processors are started through EFI MP Services only when the pool grows; later PARFOR jobs are handed to the parked workers through shared generation/work counters while the BSP participates as a worker too. This removes firmware AP-start/event/barrier overhead from repeated parallel loops. On supported processors Thoreau can enable OSXSAVE/YMM state itself on bare metal so AVX2-capable JIT paths are usable even when firmware left that state disabled. UEFI also reports framebuffer write-combining status and has a bulk fast path for graphics PUT ...,PSET presentation. Island3D joins the showcase programs in 2.5.2. It renders a first-person fractal heightfield with a 1024x1024 terrain grid by default, distance fog, directional lighting, trees and a double-buffered PARFOR column renderer. The running demo needs only a mouse: movement of the mouse looks around, the left button walks forward, the right button walks backward, and holding both buttons quits. Version 2.5.1 extends the native-execution engine with explicit multicore BASIC. PARFOR has the familiar FOR/NEXT shape but divides independent iterations among several CPU threads when the loop can be proven safe for parallel execution. Windows uses a persistent worker pool; the original 2.5.1 UEFI implementation uses firmware MP Services and lets the BSP participate. PARFOR shares one compiled native graph between workers, schedules work in chunks, keeps ordinary numeric and @ scalar scratch state private to each worker, and permits carefully proven disjoint array and framebuffer writes. OPTION PARTHREADS controls the worker limit and PARWORKERS reports the effective count used by the most recent parallel loop. Version 2.5.1 also continues the JIT performance work: native integer FOR/NEXT, more direct graphics paths, JIT-preserving PRINT/LOCATE callouts, shared PARFOR code, reduced parallel graphics bookkeeping and selected AVX2 acceleration when the CPU/OS environment supports it, with SSE2 fallback. Startup diagnostics now show keyboard capabilities, PARFOR thread capacity and SIMD availability. Octal numeric literals using GW-BASIC-style &O syntax are accepted. The 2.5 GorseGlass raytracer remains the main JIT/PARFOR stress test. Version 2.5 introduced the production x64 bytecode/JIT engine on both Windows and UEFI. Hot numeric and hypercomplex expressions, scalar and numeric/@ array access, assignments, IF/ELSE, FOR/NEXT, WHILE/WEND, DEF FN, selected graphics statements and large cross-line program regions can execute as generated x64 code. Classic GOSUB/RETURN-heavy BASIC is supported across compiled regions, including calls inside native loops and single-line IF branches. Unsupported syntax falls back to the existing interpreter automatically rather than changing program semantics. JIT is ON by default; JIT OFF forces the classic interpreter for correctness A/B tests, and PROFILE is JIT-aware. Version 2.4.1 was a development, control-flow and graphics-polish release. It added syntax-aware source tools (enhanced FIND, REPLACE, XREF and AUDIT), a statement profiler, explicit FOR END and WHILE END loop exits, REDIM, graphics slot introspection, POLYFILL, GW-BASIC DRAW P filling and an interactive Ctrl+L clear-screen shortcut. FOR and WHILE stacks each allow 4096 active loops, and mouse-click event delivery was hardened so rapid edge events are not lost between interpreter polls. Version 2.4 adds cross-platform mouse input, held-key state for simultaneous game controls, flexible video-mode discovery, and TCP/IPv4 networking with DNS and HTTP/HTTPS helpers. Windows can now use arbitrary logical framebuffer sizes and scale them into a window or fullscreen display with preserved aspect ratio. UEFI exposes real GOP modes and uses standard firmware pointer and network protocols where the machine provides them, with a raw SNP network fallback when higher-level UEFI network services are unavailable. Version 2.4 also closes several subtle GW-BASIC compatibility gaps: a leading semicolon on INPUT can suppress the final newline, NEXT can name several loop variables, and DEFINT/DEFSNG/DEFDBL/DEFLNG/DEFI64/DEFSTR now make an unsuffixed name and its matching explicit suffix refer to the same variable. Version 2.3.1 was a compatibility, debugging and usability update. It added the lazy IIF conditional expression, corrected nested single-line IF/ELSE execution, expanded the Thoreau Machine Explorer into a live debugger, reported the source line reached by STOP, and tightened program loading, directory output and Windows file-handle lifetime. Version 2.3 adds two substantial new language areas: software sprites for games and a native hypercomplex @ numeric type for higher mathematics. Sprite images and instances are separate, allowing up to 65,536 loaded images and 65,536 independent instances while many instances share one image in memory. Sprites support movement, visibility, text layering and pixel-perfect collision using precomputed transparency masks. Version 2.3 also adds game-oriented KEYREPEAT and WAITREL timing controls. The @ type covers complex numbers, quaternions and octonions in one numeric promotion tower. CPLX, QUAT and OCT construct values; arithmetic, conjugation, inverse, norm, component access and @ arrays are integrated into the expression engine. Version 2.3 also extends ^, SIN, COS, TAN, EXP, LOG, SQR/SQRT, SINH, COSH and TANH to @ values, with explicit principal-value rules where the mathematics is multivalued. Version 2.2 was primarily a compatibility, robustness and memory-management release. It added SAVEBMP, wildcard KILL, parenthesized BITBLT coordinates, automatic .BAS on SAVE, interruptible recursive DIR/FILES, compacting string garbage collection, reusable/coalescing array and bitmap memory, classic two-byte extended-key INKEY$ results, and full-width word-aware HELP. Version 2.1 adds international keyboard support to the x64 UEFI build, runtime keyboard-layout switching, and the SYSTEM command on both platforms. On UEFI, THOREAU.CFG beside the EFI can contain a DOS-style keyboard selection: KEYB GR KEYB can also switch layouts while Thoreau BASIC is running. Thoreau supports 23 layouts. When possible it reads a USB HID boot keyboard directly so physical key positions are preserved even when firmware keyboard translation is incomplete. If direct USB HID input is unavailable, it falls back to UEFI firmware input. The default layout is US. SYSTEM leaves Thoreau BASIC. On Windows it closes the application. On UEFI it returns to the firmware/caller, allowing normal firmware boot processing to continue when Thoreau was started as a boot option. Version 2.1 also includes the 2.01 compatibility refinements: RUN accepts a starting line or filename, AUTO preserves an existing line when Enter is pressed immediately at its * prompt, and bitmap slots range from 0 through 65535. Version 2.0 added standalone application creation: Windows: CREATEEXE "program" UEFI: CREATEEFI "program" The generated EXE/EFI contains the currently loaded BASIC program. When the generated application starts, it skips the normal Thoreau BASIC banner and command prompt and immediately runs the embedded program. External assets such as BMP files and save files remain ordinary files beside the application. VERSION 3.2 CHANGES =================== FILE ARRAYS, SELECTORS AND PATHS - GETFILES creates or replaces a one-dimensional string array containing matching files, child directories and, where available, the parent entry. Optional flags choose which groups to include. No GETDIRS is needed. - SELECTBOX draws a modal, multi-column selector at a physical text-cell position. Entry width, dimensions and colors are configurable. Enter or mouse double-click accepts; Escape cancels. Single and double frames use the real joined box-drawing characters from the built-in character set. - Selector updates redraw changed entries rather than repainting the entire box while idle. HELP prints each category heading once. - Filenames retain their spelling and case throughout the file APIs and monitor. DIR, FILES, GETFILES and KILL match masks case-sensitively. BASIC commands remain case-insensitive; native filesystem lookup rules still apply. - BASIC path strings can contain up to 4,095 bytes, including any appended default extension. Filesystem component limits still apply. Overlong or unrepresentable paths fail instead of being silently truncated or renamed. - CLS:RUN works in direct mode. RUN inside a stored program restarts through the execution controller instead of recursively entering the C interpreter. A program such as 10 RUN can still loop indefinitely, but Escape interrupts it without an ever-growing host stack. GENERAL-PURPOSE RECOVERY AND FILE OPERATIONS - STATEWRITE / STATELOAD save and restore an explicit variable schema using two alternating, checksummed generations, staged restore and readback verification. These are selected-state checkpoints, not a whole-machine image or an append-only journal. - FLUSH requests platform durability for open output files. FILECOMMIT promotes a staged file and retains target.previous. FILECOPY stages, flushes and byte-verifies a copy before promotion. FILECRC checks file bytes. - SESSIONLOCK prevents simultaneous Windows writers in one recovery folder. ABORTFILES closes failed output handles without retrying buffered writes. - CRC32 checks string bytes; TEXTSTATS counts words and characters in a selected range of a string array. These APIs are reusable by BASIC programs. SUPPORT AND ENGINE CHANGES - SYSTEMINFO$(0..13) reports the platform/version, firmware and input/storage details, CPUID model, usable AVX2/SSE2 path, PARFOR capacity and usage, startup-calibrated TSC MHz, arena allocation, video backend, JIT state and build/CPU identifiers. TSC MHz is a counter rate, not live CPU turbo speed. - BATTERYPERCENT(0) reports an OS/firmware battery percentage when available, otherwise -1. UEFI depends on the Battery Charging Protocol being exposed. - The floating INT JIT path uses native SSE2 with the existing floor behavior. Native hypercomplex magnitude uses a direct square root where safe and retains scaled fallbacks. Hypercomplex multiplication reduces load/operation overhead while preserving operation order and numeric fallbacks. These are interpreter changes; they do not require rewriting BASIC programs. - UEFI supplies its own strcmp implementation for the file-copy helpers, avoiding an unresolved CRT symbol in the freestanding firmware build. BUNDLED PROGRAMS - MANDELZOOM.BAS pans with mouse movement and zooms while a mouse button is held. A fixed-width FPS field occupies a reserved top text row. This example uses scalar arithmetic; it has no native-complex mode switch. The archives contain source projects. Recorded host checks do not substitute for native Windows/UEFI builds or physical power-loss and removable-media tests. VERSION 3.1 CHANGES =================== OPUS WAVETABLES AND AUDIO FILES - Lossy TBGM4 Opus bank profile with 81.4 MB, replacing the 513.5 MB lossless bank when a smaller download is preferred. All profiles contain the same 2,197 samples and preserve instrument/zone metadata. - The complete bank is expanded during loading, before music starts. The supplied banks need 1,089,637,606 bytes of PCM plus temporary worker memory and ordinary runtime memory. Compression reduces disk size, not PCM RAM. - SOUND PRELOAD [workers] uses up to eight decoders. Each worker owns its decoder and scratch memory; all workers join before PCM is published. SOUND INFO reports timing, worker counts, helper work, batches and dispatch. - UEFI Opus scratch lookup no longer repeatedly queries the CPU. Blocking firmware dispatches use full batches while sound is stopped. The loading fix has been confirmed working in VirtualBox; no new VM timing is claimed. - LOADWAV accepts WAV, native FLAC and Ogg Opus by file contents. It decodes and resamples completely at load time. PLAYWAV uses resident 48 kHz PCM, with no file reads or codec work during playback. Failed loads keep the previous slot. No external codec DLL or converter is required. LANGUAGE AND COMPATIBILITY - SOUND ON/OFF, JIT ON/OFF and state-changing PROFILE commands no longer print confirmations from stored programs. Explicit information queries still print. The PLAYMID extension warning is direct-mode only; MIDINFO remains available. SOUND PRELOAD is quiet in programs unless captured. - SOUNDGROUP(id[,engine]) returns a numeric catalog group. SOUNDNAME$ and INSTRUMENT now document their existing optional engine argument. - CAPTURE stringVar or CAPTURE [#]fileNumber redirects ordinary text and info output until CAPTURE OFF. See the reference for buffering and lifetime. - ERROR$ is a read-only stable copy of the last error text alongside ERR/ERL. - LINE INPUT accepts either comma or semicolon after a prompt; neither adds a question mark. File input syntax is unchanged. - Arrays named after built-in functions are rejected, including type-suffixed spellings. Legal scalar/function-name conflicts also produce AUDIT warnings. AUDIT may run inside a program and its output can be captured. - Exponentiation is left-associative in the interpreter, JIT and PARFOR: 2^3^2 = 64 2^(3^2) = 512 -2^2 = -4 (-2)^2 = 4 2^-3^2 = .015625 Add parentheses to old programs that relied on right-associative powers. RUNTIME AND BUILD IMPROVEMENTS - CREATEEXE file$ NOGM and CREATEEFI file$ NOGM create applications without embedding the wavetable. Without NOGM, the interpreter's embedded bank is copied, otherwise THOREAU_GM.TBGM from the current directory if present. Inclusion does not depend on whether the program uses sound or the bank has been loaded. NOGM applications can still load an external bank at runtime. - PARFOR reuses eligible compiled work across invocations while refreshing private execution state. Graphics fills use clipped spans, string paths reduce copying, and checked bulk memory operations use wider transfers. - The existing sprite dirty-area, exact audio-coefficient reuse and batched source-import improvements remain enabled. VERSION 3.0 CHANGES =================== Version 3.0 is the first Thoreau BASIC release with a complete public sampled-audio subsystem. It also includes targeted runtime optimizations which remove repeated work without changing BASIC syntax or the approved wavetable data. GENERAL MIDI / GS WAVETABLE --------------------------- - The public instrument engine is wavetable-only. General MIDI programs use Thoreau instrument IDs 0..127. Drum kits are: 128 Standard 129 Room 130 Power 131 Electronic - Each drum kit keeps the 47 standard GM percussion positions and 14 mapped GS extra percussion positions. Percussion never borrows a neighbouring drum key. - THOREAU_GM.TBGM is loaded on demand. SOUNDNAME$ and group-name queries do not need to load the bank; SOUNDAVAILABLE and actual instrument playback do. - NOTE/NOTEOFF provide ordinary MIDI-style note control. SOUNDKEY provides a stable key id plus continuous pitch, pressure, X/Y and gate values for expressive controllers. - The render domain is 48 kHz stereo. Thoreau exposes 32 instrument channels and up to 256 simultaneous note voices. LOSSLESS BANK STORAGE / PARALLEL PRELOAD ---------------------------------------- - TBGM3 stores the sample payload losslessly. Loading reconstructs the original decoded PCM and verifies the bank rather than substituting a perceptual codec. - SOUND PRELOAD performs bank loading explicitly before the first note: SOUND PRELOAD automatic worker choice SOUND PRELOAD 1 serial decode SOUND PRELOAD 2 at most two decoders ... SOUND PRELOAD 8 at most eight decoders SOUND PRELOAD 0 is the explicit automatic setting. - The caller performs file I/O while worker decoders process independent compressed blocks. The loader falls back to fewer workers or serial operation when parallel services are unavailable. - SOUND INFO reports stored/decoded bank sizes, measured load timing, decoder count, batches, dispatch/fallback state and temporary loader workspace. WAV PLAYBACK ------------ - LOADWAV loads PCM/float WAV data into slots 0..255 and converts it to the 48 kHz render domain. - PLAYWAV uses a separate pool of 64 playback channels. Omitted or -1 channel selects a free channel automatically. WAV playback does not consume GM note voices. - STOPWAV, WAITWAV, PAUSEWAV, RESUMEWAV, WAVCTL, DELWAV and WAVINFO manage the pool. WAVACTIVE, WAVPLAYING, WAVSTATE, WAVPOS, WAVLENGTH, WAVLOADED, WAVSLOT and WAVCHANNEL expose its state. - Asynchronous WAV playback survives ordinary BASIC errors, STOP and ESC. WAITWAV is the explicit wait/cancel interface. MIDI PLAYBACK AND EFFECTS ------------------------- - LOADMID loads Standard MIDI File type 0/1 and RIFF RMID data into slots 0..255. PLAYMID renders it through Thoreau's own GM wavetable rather than a platform MIDI synthesizer. - MIDI parts 0..15 map directly onto the wavetable instrument channels. STOPMID, WAITMID, DELMID and MIDINFO manage loaded scores. MIDPLAYING, MIDSTATE, MIDPOS and MIDLENGTH expose playback state. - MIDCC can send supported MIDI controllers to one part or all parts. The MIDI implementation includes the current GM/GS controller handling used by the Thoreau wavetable. - Reverb, chorus and GS-style delay use the MIDI effect sends. MIDFX provides a deliberate all-part audition override: MIDFX 127,0,0 reverb audition MIDFX 0,127,0 chorus audition MIDFX 0,0,127 delay audition MIDFX OFF force dry sends MIDFX AUTO follow the score again MIDFX CLEAR clear existing wet tails only MIDCCINFO reports live parts, effect sends and wet-return meters. - Ordinary NOTE/SOUNDKEY voices and independent WAV playback do not feed the MIDI effect processors. HANDLER-AWARE NATIVE EXECUTION ------------------------------ - Registering ON ERROR, programmable timer handlers or mouse handlers no longer automatically disables eligible native assignment/FOR/WHILE regions. - Native regions preserve source markers and live loop state so rare error/event exits can return to the interpreter with the correct BASIC location and control context. - ON BREAK and control contexts which cannot be represented safely continue to use the existing fallback rules. Unsupported code still falls back rather than changing BASIC semantics. BOUNDED SPRITE RECOMPOSITION ---------------------------- - Ordinary base-graphics writes while sprites are visible accumulate a bounded dirty rectangle where possible. - At the statement/region boundary Thoreau restores that rectangle from the sprite-free backbuffer and recomposites only sprite/text fragments intersecting it. - Full-frame refresh remains the correctness fallback for screen changes, untracked/raw writes and cases where the changed area cannot be proven. EXACT AUDIO COEFFICIENT REUSE ----------------------------- - The wavetable/MIDI renderer remembers the exact bit pattern of inputs to expensive exponential coefficient calculations. - Pitch step, release, MIDI relative controls, filter preparation and expression tilt reuse the previous result only when the exact input is unchanged. Changed inputs still execute the original formula. This is a CPU optimization, not a lower-quality sound mode. SCOPED SOURCE IMPORT -------------------- - LOAD, MERGE and CHAIN now use a scoped source-import transaction. - Token/JIT/PARFOR cache invalidation and profiler clearing requested while that transaction is active are deferred and committed once when the import ends. - A partial input error still closes the scope and performs the required invalidation, so the stored prefix and interpreter state remain coherent. VERSION 2.5.4 CHANGES ===================== Version 2.5.4 concentrates on native integer throughput and several GW-BASIC text and keyboard compatibility details. These are the changes since 2.5.3.1. INTEGER JIT / ARRAY PERFORMANCE ------------------------------- - Matching integer division and remainder expressions can reuse one x64 IDIV. For example, when the operands are unchanged between: Q=S\D R=S MOD D the JIT preserves both quotient and remainder from the first hardware divide instead of performing the same division twice. - Integer-width data-flow analysis tracks when native results are safely within narrower integer ranges without changing their BASIC-visible type. Floating operators explicitly clear this proof, preventing a floating result from being mistaken for an integer by a later fast path. - Hot integer scalars can remain in nonvolatile general-purpose registers across BASIC statements while the canonical BASIC variable is still updated normally. Integer FOR/NEXT also reuses the validated loop-variable pointer and exact induction shadow instead of repeatedly resolving and rereading the variable. - Native loop polling keeps its counter and pointer in registers on hot back edges, greatly reducing memory traffic in very large compiled loops while preserving break/event polling cadence. - One-dimensional numeric arrays have a stronger per-invocation cache for the validated data pointer, lower bound and span. Hot A(I) loads/stores therefore avoid repeated variable-table, array-header and general row-major work. LONG array addressing uses direct scaled native addressing where possible. - Simple array-store subscripts based on an untouched integer FOR variable are recognized as affine indices: A(I), A(I+constant) and A(I-constant). The address can be derived directly from the exact FOR induction shadow. The equivalent canonical subscript VALUE is still materialized before any fallback path so bounds/type errors retain ordinary BASIC semantics. - Statement assignments which immediately discard an array-store result avoid an unnecessary VALUE copy. Integer array narrowing checks and several address/store sequences were shortened as part of the same pass. - On the developer Windows test system, the unchanged 10,001-digit integer pi/dropper benchmark now runs in 11.42 s, compared with 29.75 s in 2.5.3 and 258.49 s in 2.4.1. Island3D reaches about 108 fps on that system. Performance varies with CPU, video mode and firmware. WINDOWS RAW KEYBOARD / INPUT$ ----------------------------- - TAB now reaches both INKEY$ and keyboard INPUT$(1) as CHR$(9). KEYDOWN(CHR$(9)) continues to report held state independently. - ESC during keyboard INPUT$ is returned as CHR$(27). It no longer becomes a permanently pending break key which could leave INPUT$ waiting forever. - F10 is consumed by the Thoreau window instead of toggling the Windows system menu. INKEY$ receives the normal GW/DOS extended-key pair CHR$(0)+CHR$(68). - Keyboard INPUT$(count) is a blocking, non-echoing raw character read. Ordinary control characters such as TAB and ESC pass through. For navigation/function extended keys INPUT$ returns CHR$(0); INKEY$ remains the interface that exposes the complete two-byte CHR$(0)+scan sequence. File INPUT$(count,#n) is unchanged. VIEW PRINT / LOCATE / CLASSIC PRINT CONTROL BYTES ------------------------------------------------- - VIEW PRINT restricts the active text output/scrolling region, but LOCATE row is once again an absolute whole-screen row as in GW-BASIC. LOCATE rejects rows outside the active viewport. CSRLIN reports the same absolute row coordinates. - Console PRINT now gives the classic control bytes their text-device meanings: CHR$(7) BEL; Windows issues a system beep, UEFI currently consumes it CHR$(9) TAB to the next 8-column text tab stop CHR$(10) newline, equivalent to the existing CR handling CHR$(12) clear the active text viewport CHR$(13) newline / carriage-return handling These rules apply to screen/text-window output rather than PRINT# file data. PARFOR DIAGNOSTICS ------------------ - A rejected PARFOR now prints its actionable diagnostic once. The message uses the normal word wrapper for the active text width instead of being emitted once wrapped and then a second time as an unwrapped deferred error string. - The normal BASIC source-line suffix is preserved, so the failing line remains easy to identify without duplicated or character-sliced diagnostics. VERSION 2.5.3.1 CHANGES ======================= Version 2.5.3.1 is a cumulative hotfix and performance update. These are the changes since 2.5.3. WINDOWS CLIPBOARD / TEXT ENCODING --------------------------------- - Thoreau BASIC's Windows text byte set is CP437. CLIPBOARD now converts CP437 bytes explicitly to UTF-16 before publishing CF_UNICODETEXT instead of treating byte values 128..255 as Unicode code points. - CLIPBOARD$ converts UTF-16 desktop text back to CP437. Characters which do not exist in CP437 become '?'. CR/LF is normalized to BASIC LF, and the existing smart-quote / en-dash / em-dash ASCII normalization is retained. - Ctrl+V in the command, INPUT and LINE INPUT editors uses the same conversion path as CLIPBOARD$, and ordinary Windows WM_CHAR input converts typed Unicode characters to CP437 explicitly. Accented CP437 characters therefore behave consistently whether typed, pasted or transferred through CLIPBOARD. - Opening the Windows clipboard now retries briefly (up to about 250 ms) when a clipboard history/sync tool or another process owns it momentarily. This avoids spurious Clipboard error failures in rapid write/read/restore cycles. - UEFI clipboard behaviour is unchanged: it is interpreter-local and preserves BASIC bytes exactly because firmware has no external Unicode clipboard. VIEW / DEF FN ROBUSTNESS ------------------------ - VIEW ...,border draws its border one pixel outside the graphics viewport. Border edges which fall outside the framebuffer are now clipped individually instead of suppressing the entire border. VIEW (0,0)-(120,120),1,15 therefore still draws the visible right and bottom border edges, matching GW-BASIC. - Recursive user functions now have a guarded call depth. Pathological code such as DEF FNA(X)=FNA(X) terminates with BASIC error 7 (Out of memory) instead of overflowing the native Windows/UEFI C stack and crashing Thoreau. TRACE ----- - TRACE var[,var...] is now a change watch. It prints only when at least one watched scalar changes, instead of dumping every watched value on every source line. Every message is prefixed with the BASIC source line which caused the change, for example: [120] {Q=6} [370] {Q=5 SCORE%=42} - TRACE is semantically complete with JIT ON. While watches are active, cross-line JIT regions and compiled multi-statement loop/flow fast paths step aside so no changes are skipped. Safe single-statement JIT execution remains. JIT / PARFOR PERFORMANCE ------------------------ - The cross-statement DOUBLE register cache now uses up to ten nonvolatile XMM registers (XMM6..XMM15). Compiled regional GOSUB no longer disables the whole cache: after a call, only entries which the reachable callee graph can write are reloaded. - PARFOR resolves compiled regional GOSUB targets once when the shared worker graph is prepared instead of searching the region table on every call. - JIT back-edge polling inside PARFOR now uses a persistent worker-local counter instead of one global counter shared by all cores. This removes a hot cache-line contention point while preserving break/abort polling cadence. - Native array indexing has an exact-integer fast path for floating BASIC subscripts. Validated PARFOR one-dimensional arrays can reuse invariant array metadata directly, and a proven exact-integral DOUBLE FOR variable can supply its INT64 induction shadow directly to one-dimensional array subscripts. - Proven untouched DOUBLE FOR loops whose start, limit and STEP are exact integers can use an INT64 induction shadow for NEXT while the canonical BASIC variable remains DOUBLE. Non-integral or uncertain loops retain the existing floating path automatically. - Successful native statements keep the current BASIC source line in a nonvolatile register instead of storing it to JIT context memory on every statement. The line is committed on an error/fallback exit, preserving precise ERL/error attribution with less hot-path bookkeeping. PROFILE / PARFOR ---------------- - PROFILE ON, PROFILE JIT and PROFILE SAMPLE now work inside PARFOR. Each worker has an independent randomized sampling stream which persists across regional GOSUB/RETURN boundaries, and sampled timing is accumulated safely across workers. - Parallel timing rows are labelled PAR. Their TIME/SHARE values are sampled worker CPU time; RUNS/JITRUNS/INTRUNS are deliberately left at zero for those rows rather than adding a contended shared execution counter to every hot line. - PROFILE EXACT / PROFILE INTERPRETER still disable JIT execution and therefore cannot execute PARFOR; use ordinary FOR when exact interpreter profiling is required. DOCUMENTATION ------------- - The 2.5.3 release notes now explicitly mention the shared command/INPUT/ LINE INPUT insert/overwrite mode and its steady cursor-shape indication. VERSION 2.5.3 CHANGES ===================== Version 2.5.3 combines GW-BASIC compatibility work with graphics-text, clipboard, error-handling and UEFI display/input improvements. DISPLAY / UEFI PERFORMANCE -------------------------- - Faster text output uses SSE2 glyph stores and bulk scanline scrolling where available. LIST also avoids a redundant full source-line display-row scan. - UEFI framebuffer presentation was reworked for machines where direct GOP framebuffer writes are slow or firmware refuses the caching request. Thoreau retains the write-combining request where possible and can present a cached RAM backbuffer through GOP BLT. - GOP-BLT presentation is frame-oriented/throttled rather than copying the complete frame after every tiny change. Long interpreted and JIT graphics workloads receive live presentation opportunities, while blocking input, HELP pagination and end-of-RUN force pending graphics to the screen. - Bulk CLS/fill/scroll/glyph/horizontal-line operations reduce framebuffer traffic. UEFI key polling uses WaitForKey gating, mouse polling is skipped when not needed, and a stationary software pointer is not continually repainted. TIMER and mouse callbacks remain non-preemptive. UEFI INPUT / MOUSE ------------------ - Ctrl+A through Ctrl+Z are normalized to ASCII control codes 1..26, matching the Windows/INKEY$ convention. - Double-click detection now derives from the ordinary queued click stream. Pointer selection no longer abandons an idle device merely because it returned EFI_NOT_READY; the first genuinely moving pointer locks in, and movement accumulators are reset when switching/probing. - Mouse text-coordinate conversion now uses the real 8x16 character geometry. CLIPBOARD --------- - CLIPBOARD stringExpr writes text to the clipboard and CLIPBOARD$ reads it. Windows uses the desktop Unicode clipboard and, as of 2.5.3.1, explicitly converts to/from BASIC CP437 bytes. UEFI provides an interpreter-session byte clipboard because firmware has no standard system clipboard service. - Ctrl+V reaches INKEY$ as CHR$(22). On Windows, clipboard open operations retry briefly when another clipboard consumer temporarily owns the clipboard, fixing repeated-run clipboard round trips. ERROR HANDLING / INPUT ---------------------- - The command editor, INPUT and LINE INPUT now share the same insert/overwrite editing state. INSERT toggles the mode and the steady cursor shape reflects the active semantics while editing. - Explicit RESUME line clears abandoned GOSUB/FOR/WHILE/IF and timer/mouse handler state before transferring control. - OPTION ERRORPRINT 0|1 controls diagnostic printing of successfully trapped errors. The default is 0: ON ERROR GOTO fills ERR/ERL and transfers silently, matching GW-BASIC. Unhandled errors always print. OPTION ERRORPRINT 1 restores visible trapped-error diagnostics when debugging. - INPUT distinguishes malformed input from numeric overflow. A type mismatch in interactive input still prints ?Redo from start; an out-of-range numeric value raises Overflow and can be caught by ON ERROR GOTO. - Errors raised inside a compiled JIT region now preserve the actual BASIC source line in ERL/error reporting instead of blaming the region entry line. DATA / READ / RESTORE --------------------- - Empty DATA fields now follow GW-BASIC, including a bare DATA statement and a trailing comma. Consecutive commas continue to represent empty values. - DATA is a statement rather than the rest of the physical line. A colon ends it, DATA may follow another statement on the same line, and statements after DATA execute normally. Quoted colons stay inside DATA strings and comments terminate source scanning correctly. Multiple DATA statements on one physical line are supported. - RESTORE line now requires that exact program line to exist. If it does, READ resumes at the first DATA statement at or after that line; otherwise Thoreau raises Undefined line number. DEF FN ------ - DEF FN enforces the function name's suffix/default return type and captures unsuffixed parameter types from the active DEFxxx defaults when the DEF line executes. Interpreter and JIT share the same parameter/result coercion rules. - GW-BASIC's spaced form is accepted contextually: DEF FN Name(...) and FN Name(...), without reserving FN globally. GRAPHICS TEXT ------------- - GPRINT [STEP](x,y),text$[,fg[,bg]] draws the normal 8x16 glyphs at exact graphics coordinates. The current foreground is used when fg is omitted. Omit bg for transparent text; supply it to paint the entire glyph cell. STEP and VIEW/WINDOW coordinate mapping are supported. GW-BASIC PARSER / CONTROL FLOW ------------------------------ - THEN is required after IF except for GW-BASIC's IF condition GOTO line form. Independent statements on one physical line must be separated by a colon. - Elided IF THEN/ELSE line targets are literal line numbers. Expressions such as THEN 10+10 are rejected instead of being partially parsed. Explicit GOTO expression and GOSUB expression remain intentional Thoreau extensions. - ON expr GOTO/GOSUB target lists require literal line numbers. Selector values below 0 or above 255 raise Illegal function call; 0 or a selector within 0..255 but beyond the supplied list falls through to the next statement. - RENUM rewrites only complete literal line references, so computed targets are not partially corrupted. It also follows Thoreau TRON ranges and GW-BASIC CHAIN ... DELETE ranges. CHAIN's destination-program start line is deliberately not renumbered because it belongs to the program being loaded. HYPERCOMPLEX COMPARISON ----------------------- - Native @ values support = and <> in both interpreter and JIT paths as the documentation promises. Components are compared after dimensional promotion. Hypercomplex ordering (<, <=, >, >=) remains invalid. REGRESSION COVERAGE ------------------- - THOREAU_SELFTEST.BAS has been expanded to 29 automated tests covering the major interpreter/JIT compatibility paths, including DATA/RESTORE, DEF FN, hypercomplex comparison, clipboard, ON ERROR/RESUME, parser rules and JIT error-line attribution. VERSION 2.5.2 CHANGES ===================== Version 2.5.2 concentrates on making long-running and repeatedly invoked JIT workloads behave like a runtime rather than a sequence of fresh compilations. - Repeated PARFOR source regions are cached by source location, callable mode and bytecode epoch. A loop executed once per frame therefore reuses its compiled region graph instead of consuming more of the code/token arena on every frame. - RUN is a compile-cache boundary. Thoreau flushes token/bytecode/native-JIT cache state before BASreset recreates variables and arrays, preventing stale cached variable identities from surviving into a second RUN. - Windows and UEFI discard queued gameplay key events when RUN or CONT returns to Ready. KEYDOWN remains non-consuming while a program runs, but keypresses accumulated by a game no longer reappear later in the command editor, INKEY$, INPUT$, or a LIST paging prompt. - x64 UEFI PARFOR now keeps a persistent application-processor worker pool for the lifetime of a BASIC RUN. APs are started through EFI MP Services only when the pool grows; later PARFOR jobs are published through shared generation/work counters. The BSP remains a worker. This removes repeated StartupThisAP/event creation/firmware wait overhead from frame-by-frame parallel loops. - On bare-metal x64 UEFI, Thoreau can enable CR4.OSXSAVE and the SSE/YMM XCR0 state itself when CPUID reports XSAVE, AVX and AVX2 support. The startup diagnostic distinguishes AVX2 hardware whose YMM state was enabled by Thoreau from environments where it was already enabled. Each persistent AP initializes its own processor state when it joins the PARFOR pool. - UEFI startup also reports whether the GOP framebuffer was successfully set to write-combining memory. Graphics PUT ...,PSET has a bulk SSE2 copy path with non-temporal stores to the visible framebuffer, reducing full-frame presentation overhead. - Island3D is added as a 2.5.2 showcase for the combined JIT, PARFOR, mouse and graphics paths. The supplied configuration uses a 640x480 view over a 1024x1024 fractal heightfield (VOX=4), with fog, directional terrain lighting, trees and a double-buffered parallel column renderer. VERSION 2.5.1 CHANGES ===================== Version 2.5.1 focuses on parallel execution and further JIT/runtime performance without changing the classic interpreter semantics. - PARFOR adds explicit data/iteration parallelism using familiar BASIC syntax: PARFOR Y=0 TO GRAMAXY ...independent work for Y... NEXT Y PARFOR is intentionally opt-in. Ordinary FOR retains its normal sequential semantics. A PARFOR body must stay fully JIT-compilable and every iteration must be safe to execute independently. The compiler validates the complete reachable control-flow/GOSUB graph before starting workers and rejects unsafe loops with a source-aware explanation, the offending command and a suggested workaround. - Numeric and @ scalar variables used as PARFOR scratch state are private to each worker. Shared numeric/@ arrays may be read normally. Array stores are accepted only when Thoreau can prove them disjoint between iterations, for example A(I)=... under PARFOR I or B(X,I)=... under PARFOR I. Ambiguous shared writes are rejected rather than raced. - Absolute PSET and supported LINE forms with explicit colours can be used as PARFOR output when iterations draw independent pixels/regions. WINDOW/VIEW dependent drawing is rejected because it relies on shared transform state. Text output/cursor operations and other shared interpreter state remain outside PARFOR. - PARFOR currently supports integer start/limit values and a positive integer STEP. Nested PARFOR is deliberately rejected and JIT must be ON. TRON/TRACE, debugger breakpoints and interpreter event handlers must be disabled while a PARFOR executes. As of 2.5.3.1, sampled PROFILE ON/JIT/SAMPLE is supported in PARFOR; PROFILE EXACT/INTERPRETER disables JIT and therefore still requires FOR. - OPTION PARTHREADS 0 selects automatic worker tuning. Small loops may stay on one worker when parallel launch/barrier cost would be larger than the work. OPTION PARTHREADS n (1..32) caps the requested worker count. PARTHREADS reads the configured value; PARWORKERS reports the effective number used by the most recent PARFOR. Startup also reports how many CPU threads are available to PARFOR on the current machine/firmware. - Windows uses a persistent PARFOR worker pool. UEFI uses EFI MP Services and includes the BSP as a worker when possible. Workers dynamically claim chunks of iterations, reducing synchronization overhead while preserving load balancing. The same position-independent native PARFOR graph is shared by all workers instead of compiling one code copy per worker. - Parallel framebuffer drawing avoids needless per-pixel updates of shared graphics bookkeeping and consolidates those updates at the PARFOR barrier, reducing cache-line contention between cores. - The JIT gains native fast paths for horizontal/vertical LINE, boxes and filled boxes where semantics permit; PRINT and LOCATE can call the canonical statement implementation without tearing down an otherwise native region; and integer FOR/NEXT now has a corrected native fast path. - Selected hypercomplex component operations can use AVX2 when the processor and execution environment expose usable AVX2/YMM state. SSE2 remains the baseline fallback. Startup reports which SIMD path is available to the JIT. - Startup diagnostics are grouped into keyboard, CPU/PARFOR and SIMD blocks. Keyboard output identifies the active backend and whether KEYDOWN and KEYREPEAT delay/rate control are available. - GW-BASIC-style octal literals are accepted with &O, for example &O10 (8) and &O377 (255), alongside the existing &H hexadecimal syntax. - PARFOR diagnostic messages wrap to the active text-window width so their detailed reason/workaround text remains readable on narrow screens. - SPRITEOFF is documented: it deletes all active sprite instances at once but keeps loaded sprite images available for later SPRITE commands. VERSION 2.5 CHANGES =================== Version 2.5 turns the experimental bytecode/JIT work into a normal execution engine on Windows x64 and x64 UEFI. The classic interpreter remains the semantic fallback and can be forced explicitly with JIT OFF. - JIT is enabled by default. JIT ON enables all bytecode/native acceleration; JIT OFF forces the classic interpreter for expressions, assignments, control flow, loops and compiled program regions. Bare JIT reports the current state. Changing the state flushes native JIT pages. - Stored-program expressions and statements can be compiled once and reused. The production engine covers scalar numeric arithmetic/comparisons, native @ hypercomplex operations, DEF FN expression bodies, numeric/@ arrays, scalar assignments, IF/ELSE, FOR/NEXT and WHILE/WEND, plus selected graphics paths including PSET/PRESET, LINE and COLOR. Unsupported syntax simply falls back. - Cross-line PROGRAM regions keep larger stretches of ordinary line-numbered BASIC in compiled execution rather than accelerating isolated expressions only. Nested single-line IF constructs preserve nearest-ELSE semantics. - Literal GOSUB/RETURN is supported inside compiled regions. Cross-region subroutine calls are preflighted and can execute synchronously without dropping native FOR/WHILE state. When a call must fall back to the classic interpreter, its BASIC return point and single-line IF context are preserved. - The JIT includes native handling and caching aimed at classic loop-heavy BASIC: numeric/@ arrays, FOR/NEXT regions, hypercomplex arithmetic, small integer powers, repeated subroutine targets and reusable compiled blocks. - PROFILE is JIT-aware. PROFILE ON, PROFILE JIT and PROFILE SAMPLE use the compiled engine with randomized low-overhead timing samples. PROFILE EXACT and PROFILE INTERPRETER use exact interpreter timing and disable compiled fast paths while profiling. Reports include RUNS, JITRUNS, INTRUNS and MODE; MODE distinguishes JIT, INT and mixed execution. PROFILE MARK (also PROFILE MARK ON or PROFILE ON MARK) starts the normal JIT-aware sampled profiler and records which engine executed each statement for colour-coded LIST output. Green means executed by JIT; yellow means interpreted although the statement itself is JIT-capable; red means interpreted and not JIT-supported; normal text means the statement was not reached. PROFILE MARK OFF restores ordinary LIST colours without discarding collected statistics. PROFILE OFF retains samples and the last MARK colours; PROFILE CLEAR discards statistics and marks. - Windows allocates executable JIT pages through the native virtual-memory layer. UEFI allocates runtime-generated code as EfiLoaderCode pages through Boot Services and releases them when the JIT cache is flushed. - JIT OFF is deliberately broader than a native-code switch: it disables the bytecode VM too. This provides a clean interpreter-vs-JIT correctness test. - GorseGlass is added as a v2.5 showcase and stress test. It renders a 1024x768 scene with analytic spheres, a checkerboard floor, hard shadows, Phong highlights, reflection, true entry/exit Snell refraction and Schlick Fresnel blending. The distributed version keeps the visually stronger quality path. VERSION 2.4.1 CHANGES ===================== Version 2.4.1 concentrates on development ergonomics, structured exits, arrays and graphics convenience while retaining the 2.4 language and platform model. - FIND gains FIND NEXT and FIND PREV to continue the previous search, optional WORD matching for complete BASIC identifiers, and the existing line-range restriction. Ordinary FIND remains a case-insensitive textual search and therefore still sees strings and comments. - REPLACE old$,new$[,range][,WORD] edits stored source directly. Plain mode performs case-insensitive literal replacement. WORD mode is intended for safe symbol renaming: it requires BASIC names and ignores quoted strings, REM/apostrophe comments and DATA. Replacement is preflighted so an overlong source line or full code arena leaves the program unchanged. - XREF name, XREF array() and XREF line provide syntax-aware cross-reference searches. The line form follows literal GOTO, GOSUB, THEN, ELSE, RESTORE, RESUME and ON targets and reports whether the target line exists. - AUDIT performs a static source pass for undefined literal line targets, source-order FOR/NEXT and WHILE/WEND mismatches, and parenthesized FN calls that have no DEF FN. Strings, comments and DATA are ignored. - PROFILE ON clears and starts line profiling; PROFILE OFF stops measurement while retaining samples; PROFILE shows the 20 hottest lines; PROFILE ALL prints all sampled lines in source order; PROFILE CLEAR discards samples. Output uses aligned LINE/RUNS/TIME/SHARE/SOURCE columns. - FOR END exits the innermost active FOR and continues after its matching NEXT. WHILE END does the same for WHILE/WEND. FOR and WHILE runtime stacks now each permit 4096 active loops. - REDIM array(bounds) creates an array if absent or replaces an existing one. Existing contents are discarded and the array address may change. ERASE of a nonexistent array is now harmless, simplifying subprograms that allocate result arrays on demand. - POLYFILL fills arbitrary polygons with the even-odd rule and accepts palette colors, packed 24-bit RGB or r,g,b triples. STEP vertices are relative to the previous vertex. Up to 4096 vertices are accepted. - DRAW adds the classic Ppaint,border Graphics Macro Language command, using the same flood-fill engine as PAINT. - Bitmap slots can be queried with BMPLOADED(), BMPWIDTH() and BMPHEIGHT(). Sprite-image slots add SPRITELOADED(), SPRITEWIDTH(), SPRITEHEIGHT() and SPRITEKEYCOLOR(). LOADBMP has no stored key color because BITBLT transparency is selected per draw operation. - SCREEN(row,col) returns the character code stored in a text cell. There is no PC-style attribute-byte form because Thoreau's display is a 24-bit framebuffer with a separate text grid rather than VGA text memory. - Ctrl+L at the interactive prompt clears the display and the current edit line. It is not an asynchronous CLS shortcut while a BASIC program runs. - ON MOUSECLICK delivery now queues button-down edges so clicks are not lost merely because several arrive between interpreter statement polls. VERSION 2.4 CHANGES =================== Version 2.4 extends Thoreau BASIC in four practical areas: input, video, networking and compatibility. - KEYDOWN(key$) reports whether a key is currently held without consuming INKEY$. Multiple keys can therefore be tested in the same game frame. Named keys include LEFT, RIGHT, UP, DOWN, SPACE, ENTER, ESC, TAB, HOME, END, INSERT, DELETE, PAGEUP, PAGEDOWN, SHIFT, CTRL, ALT and F1 through F12. Single-character strings and classic CHR$(0)+scan extended-key strings are accepted too. KEYSTATEAVAILABLE reports whether genuine held-key state is available. Windows always provides it while the Thoreau window is active; UEFI provides it through the raw USB HID keyboard backend. Firmware text input cannot provide reliable key-release state. - Mouse support is available on both platforms. MOUSE ON/OFF controls pointer visibility, MOUSEPOS sets its logical position, and MOUSEX(), MOUSEY(), MOUSEB(), MOUSEWHEEL() and MOUSEPRESENT expose state. Windows uses the native pointer. UEFI uses EFI_SIMPLE_POINTER_PROTOCOL with EFI_ABSOLUTE_POINTER_PROTOCOL fallback and draws a 12x18 black/white software pointer as a topmost layer, so moving it does not damage BASIC graphics. - ON MOUSEMOVE GOSUB line and ON MOUSECLICK GOSUB line provide non-preemptive mouse events dispatched between BASIC statements. Movement events are coalesced and capped at about 200 handler calls per second. Mouse clicks fire on button-down edges. Handler line 0 disables the corresponding event. - Windows SCREEN width,height now accepts arbitrary logical framebuffer sizes from 8x16 through 8192x8192, subject to a 64-million-pixel safety cap. A window is scaled down when necessary to fit the monitor work area. F11 fullscreen preserves the BASIC aspect ratio and fills unused space with black bars rather than changing the desktop display mode. - UEFI SCREEN width,height continues to select an exact GOP resolution. Both platforms add SCREEN MODES, VIDEOMODES(), VIDEOMODE n,widthVar,heightVar and SCREEN MODE n. On Windows the enumerated list contains unique physical resolutions reported by the monitor containing the Thoreau window; selecting one changes the logical BASIC framebuffer, not the Windows desktop mode. On UEFI the list and selection map directly to GOP modes. - TCP/IPv4 networking is available through eight client slots (0..7). TCP OPEN, TCP SEND, TCP CLOSE and TCP TIMEOUT are joined by TCPRECV$(), TCPCONNECTED(), TCPEOF(), DNS$(), NETPRESENT(), NETERROR$(), HTTPGET$() and HTTPSTATUS(). NETINFO displays network backend, protocol availability, configuration and diagnostic state. HTTPGET$ accepts HTTP or HTTPS URLs and optional CR/LF-separated request headers, returning response bodies up to 1 MiB. Network failures are reported through NETERROR$ so ordinary connection failures do not have to abort a BASIC program. - Windows networking uses Winsock and WinHTTP. UEFI prefers the standard DNS4, TCP4 and HTTP service-binding protocols. If higher-level UEFI networking is missing or unusable but Simple Network Protocol is available, Thoreau can use its own raw-SNP Ethernet/ARP/DHCPv4/IPv4/UDP/DNS/TCP stack for DNS, TCP and plain HTTP. HTTPS remains on the firmware HTTP/TLS path. - INPUT accepts GW-BASIC's leading-semicolon form, for example INPUT ;"A=",A. The final Enter does not advance to the next text line. - NEXT accepts comma-separated loop variables, for example NEXT K,J,I, closing nested FOR loops in the listed order. - DEFxxx default typing now follows GW-BASIC variable identity. After DEFINT I-N, I and I% are the same variable. After DEFDBL R-T, R and R# are the same variable. Explicit suffixes of a different type remain distinct. VERSION 2.3.1 CHANGES ===================== Version 2.3.1 builds on 2.3 without changing existing program syntax: - IIF(condition,ifTrue,ifFalse) adds a conditional expression, particularly useful inside DEF FN definitions. The condition is evaluated first and only the selected result expression is evaluated. The unselected branch cannot cause an error or side effect. For example, IIF(X=0,0,1/X) is safe at zero. - Nested single-line IF/ELSE statements now follow the classic dangling-ELSE rule: ELSE binds to the nearest unmatched IF. A false outer IF skips the complete nested THEN clause, including any ELSE belonging to an inner IF. - IF branches that execute GOSUB now retain their enclosing single-line IF context across the subroutine call, so RETURN resumes at the correct ELSE or end of statement instead of producing a Syntax Error. - STOP reports its source line as "Break in n". CONT still resumes after the STOP, and the Machine Explorer records the last pause reason and location. - The Machine Explorer has live, read-only interpreter views: STATE summarizes execution and memory use, STACK displays GOSUB/timer returns, FLOW displays FOR/WHILE/handler/single-line-IF frames, BREAKS shows pause and breakpoint state, TIMERS shows programmable timers, and INTERNALS lists core structure addresses and capacities. - F12 enters DebuggerMode from a running program, INPUT, or the BASIC prompt. Entry clears the debugger screen, uses normal key repeat and temporarily hides sprites. X restores the exact framebuffer, text grid, cursor, colors, views, sprite presentation and prior KEYREPEAT settings, then resumes the program or returns to the prompt. THOREAU uses the same protected session. - LOAD, BREAK, CLEAR and NEW clears source-line breakpoints. - DIR and FILES display filenames, directory names and paths in uppercase, while retaining directories-first, case-insensitive sorting and [DIR] markers. - Windows keeps BASIC's current directory separate from the process current directory and opens ordinary files with delete-sharing. LOAD, RUN and LOADSPRITE close their source/asset handles promptly, so a game's directory may be renamed or deleted after loading unless it contains the running EXE. VERSION 2.3 CHANGES =================== Version 2.3 introduces sprites, game-loop timing controls and hypercomplex numbers: - Software sprites separate loaded images from instances. Up to 65,536 image slots and 65,536 instances are available, so many copies can share one bitmap in memory. Sprite dimensions may exceed the current screen and are clipped while drawing. - LOADSPRITE optionally defines a transparent color. A compact 1-bit opacity mask is generated at load time. SPRITECOLLIDE first rejects non-overlapping bounding boxes, then tests the common area for exact overlap of two non-transparent pixels. One opaque-pixel overlap is a collision. - SPRITE, MOVESPRITE, SHOWSPRITE, HIDESPRITE and DELSPRITE manage persistent sprite instances. SPRITEX and SPRITEY expose instance positions. - SPRITETEXT UNDER|OVER selects whether text ink is composited below or above software sprites. UNDER is the compatibility default; OVER is useful for score displays, HUDs and labels. - KEYREPEAT delay,rate provides game-style keyboard repeat timing on Windows and raw USB HID UEFI. KEYREPEAT DEFAULT restores normal platform behavior. Firmware-input UEFI fallback cannot override repeat because UEFI text input does not expose reliable key-release state. - WAITREL milliseconds provides relative frame pacing. Work done between calls counts toward the requested interval; late frames return immediately and re-anchor instead of producing a burst of catch-up frames. WAITREL 0 resets its timing reference. - The new @ numeric type adds complex numbers, quaternions and octonions as one hypercomplex promotion tower. CPLX, QUAT and OCT construct values. - @ values support +, -, *, /, = and <> with automatic promotion from real to complex to quaternion to octonion. Quaternion/octonion multiplication keeps its mathematical non-commutative behavior, and octonion multiplication is correctly non-associative. - CONJ, INV, NORM, NORM2, ABS and COMP operate on hypercomplex values. Named component access such as Z@.R, Z@.I, Q@.J and O@.E7 is supported, including component assignment. @ arrays are supported as ordinary BASIC arrays. - ^ accepts an @ base with an ordinary real scalar exponent. Integer powers use exponentiation by squaring; non-integer powers use the documented principal value EXP(exponent*LOG(base)). A@^B@ is intentionally rejected because quaternion multiplication is non-commutative and octonions add non-associativity, so there is no single unsurprising exponent convention. - SIN, COS, TAN, EXP, LOG, SQR/SQRT, SINH, COSH and TANH accept complex, quaternion and octonion @ values. LOG, SQRT and non-integer powers use a deterministic principal branch. Negative real quaternions choose +i; negative real octonions choose +e1. - ASCII LOAD and MERGE accept literal TAB characters (CHR$(9)) from external editors. Tabs are expanded to the next 4-column tab stop before the source line is stored, so LIST displays normal spaces rather than control glyphs. - Hypercomplex division, INV, ABS and NORM use scaled numerical algorithms to avoid avoidable overflow/underflow for very large or very small components. - Scalar and hypercomplex floating-point narrowing now reports Overflow rather than silently storing infinities where the BASIC type cannot represent the result. - Windows BLOAD/BSAVE use guarded memory access, so invalid process addresses become BASIC errors instead of crashing the interpreter. - SAVE and buffered PRINT# propagate disk write failures as Disk I/O error. - Apostrophe comments now terminate the token stream correctly after any statement element, including PRINT separators. For example: 10 PRINT "_"; ' Empty cell is accepted as expected. - WHILE now rejects trailing unparsed expression text instead of silently treating it as part of the loop structure. This catches mistakes such as WHILE NOR EOF(1) with a Syntax Error while still allowing NOR as an ordinary variable name. - DIR and FILES mark directories with [DIR], list directories before files, and sort names case-insensitively within each group. This also applies to wide directory listings. - Windows BLOAD and BSAVE validate memory accesses through Thoreau's guarded memory layer. UEFI deliberately retains raw bare-metal memory semantics. SAVE and buffered file output now propagate disk write failures as "Disk I/O error". VERSION 2.2 CHANGES =================== Version 2.2 collects compatibility, memory-management and usability fixes: - Strings are reclaimed automatically by a compacting garbage collector, so repeated concatenation and reassignment no longer steadily exhaust string space. - ERASE returns numeric/string-array descriptor blocks to a coalescing free list. Live arrays never move, so VARPTR addresses remain stable. - Loaded bitmaps use the same reusable arena. Replacing a LOADBMP slot returns the old pixel block, and failed loads release temporary allocations. - FRE(0) includes reusable reclaimed array/bitmap blocks instead of reporting only the untouched gap at the top of the arena. - SAVEBMP writes the active graphics VIEW, the full screen, or an explicit rectangle as an uncompressed 24-bit BMP. - BITBLT accepts both slot,x,y and slot,(x,y) destination syntax. - KILL accepts DOS-style * and ? wildcards. Matching is case-insensitive, non-recursive and never removes directories. - SAVE appends .BAS when the final path component has no extension. - Recursive DIR/FILES output can be aborted with ESC while traversal is in progress. - HELP uses the full physical text screen rather than an 80-column cap. It wraps at word boundaries and temporarily ignores TXTWINDOW and VIEW PRINT while the HELP interface is displayed. - INKEY$ returns classic Microsoft BASIC/DOS two-byte strings for supported extended keys on both Windows and UEFI: CHR$(0)+CHR$(scan). This includes the cursor/navigation keys and F1 through F10. PLATFORMS --------- Windows x64 - Native 64-bit Windows application. - BASIC program can be supplied as an autostart file. - COMMANDLINEARG$(n) exposes arguments passed to BASIC programs. - CREATEEXE creates a standalone Windows application. - SYSTEM closes Thoreau BASIC and exits the Windows process. x64 UEFI - Runs directly as an EFI application, with no operating system required. - Uses UEFI graphics and filesystem services. - STARTUP.BAS can automatically load and run at interpreter startup. - THOREAU.CFG beside the EFI can select an international keyboard layout. - KEYB can report or switch the active keyboard layout at runtime. - Compatible USB HID boot keyboards can be read directly; firmware input is used as a compatibility fallback when raw HID takeover is unavailable. The fallback keeps non-raw-HID keyboards usable but cannot provide independent key-up/repeat timing or recover keys the firmware does not expose. - CREATEEFI creates a standalone EFI application. - SYSTEM returns to the UEFI firmware/caller. - A generated EFI application can be used as \EFI\BOOT\BOOTX64.EFI on a suitable x64 UEFI boot volume. QUICK START ----------- 10 CLS 20 PRINT "HELLO FROM THOREAU BASIC" 30 FOR I=1 TO 5 40 PRINT I 50 NEXT I 60 END RUN Program files are plain ASCII BASIC source files. Literal TAB characters from external editors are accepted by LOAD and MERGE and expanded to 4-column tab stops before storage. Classic-style LOAD shorthand is supported: LOAD "GAME LOAD "GAME.BAS Both are valid. If LOAD is given a filename without an extension, .BAS is appended. The closing quote may be omitted for LOAD. RUN accepts a stored line number or a filename as well as the traditional bare form: RUN RUN 1000 RUN "GAME RUN "GAME.BAS" RUN with a filename uses LOAD semantics first. A missing extension defaults to .BAS, and the closing quote may be omitted just as with LOAD. Save a program (the .BAS extension is added when omitted): SAVE "GAME",A Create a standalone application after loading/editing the program: CREATEEXE "GAME" Windows -> GAME.EXE CREATEEFI "GAME" UEFI -> GAME.EFI THOREAU BASIC FEATURES NOT PRESENT IN GW-BASIC ============================================== The language intentionally resembles GW-BASIC, but Thoreau BASIC is not a byte-for-byte clone. These are major Thoreau additions or substantial extensions beyond GW-BASIC: 1. NATIVE 64-BIT WINDOWS AND BARE-METAL UEFI Thoreau BASIC runs as a native x64 Windows program and as an x64 EFI application directly under firmware, without DOS or another operating system. 2. CREATEEXE / CREATEEFI The currently loaded BASIC program can be packaged into a standalone Windows EXE or UEFI EFI application. CREATEEXE "MYGAME" CREATEEFI "MYGAME" By default, packaging includes the bank embedded in the running interpreter, or otherwise THOREAU_GM.TBGM from the current directory if it is present and nonempty. It copies the stored bank bytes, including Opus compression; it does not inspect the program for music commands or require SOUND PRELOAD first. If neither source exists, the application is created without a bank. To omit the bank explicitly, put NOGM outside the quoted filename: CREATEEXE "MYGAME" NOGM CREATEEFI "MYGAME" NOGM NOGM also removes a bank inherited from the interpreter's embedded resources. The application still contains its BASIC program and the sound engine. For GM notes or MIDI playback, supply THOREAU_GM.TBGM separately in its runtime working directory. WAV/FLAC/Opus file playback does not require the GM bank. Other external assets are not bundled automatically. 3. 64-BIT INTEGER TYPE The && suffix and DEFI64 provide signed 64-bit integers. A&&=9223372036854775807 DEFI64 A-Z 4. 64-BIT ADDRESS-ORIENTED BASIC VARPTR returns 64-bit addresses. LOMEM, HIMEM, FREEBOT, FREETOP and THOREAUADR expose the interpreter and machine memory layout. 5. WIDE PEEK/POKE PEEK16, PEEK32, PEEK64 and POKE16, POKE32, POKE64 complement byte PEEK/POKE. 6. THOREAU MACHINE EXPLORER THOREAU opens a built-in low-level machine monitor with memory dumps, searches, transfers, maps, landmarks and machine information. 7. STORAGE / BOOT ARCHAEOLOGY The Machine Explorer can inspect disks, sectors, partitions, filesystems, UEFI boot entries and perform best-effort installed-OS detection. Storage inspection commands are read-only. 8. 24-BIT GW-BASIC GRAPHICS EXTENSIONS Classic GW-BASIC-style PSET, PRESET, LINE, CIRCLE, PAINT, COLOR, POINT, GET/PUT, DRAW, VIEW and WINDOW operate on a 24-bit RGB framebuffer. Palette colors 0-15 remain compatible, while direct 0xRRGGBB values are accepted throughout. PSET/PRESET, LINE, PAINT and COLOR also accept r,g,b component triples. PSET (10,10),255,136,0 LINE (20,20)-(300,180),30,80,160,BF CIRCLE (320,240),100,&HFF8800 COLOR 255,255,255,16,16,16 POINT returns raw 24-bit RGB for non-palette pixels, and graphics GET/PUT preserve full 24-bit pixels. 9. BMP GRAPHICS LOADBMP loads uncompressed 24/32-bit BMP files into slots 0..65535, BITBLT draws them, and SAVEBMP writes the current graphics VIEW, full screen, or an explicit rectangle as a 24-bit BMP. BITBLT accepts either flat x,y coordinates or a GW-style (x,y) point and can use a transparent color key. LOADBMP 0,"ROOM.BMP" BITBLT 0,(0,0) BITBLT 0,(100,80),&HFF00FF SAVEBMP "SCREEN.BMP" 10. FRAMEBUFFER INTROSPECTION GRAMAXX, GRAMAXY, GRAPITCH and SCRNADR expose graphics dimensions and the framebuffer address. 11. EXTENDED SCREEN SELECTION SCREEN width,height selects by dimensions rather than the classic GW-BASIC mode-number model. Windows accepts arbitrary logical framebuffer sizes; UEFI selects exact GOP modes. SCREEN MODES, SCREEN MODE n, VIDEOMODES() and VIDEOMODE expose the physical/display mode list. 12. TXTWINDOW AND NAMED TEXT WINDOWS TXTWINDOW can set the default text rectangle and create named @n windows. PRINT @n, CLS @n and LOCATE @n can address those regions. 13. PRINT WRAP / PRINT JUSTIFY Long prose can be word-wrapped or fully justified directly by PRINT. PRINT WRAP 60,TEXT$ PRINT JUSTIFY 60,TEXT$ 14. MULTIPLE PROGRAMMABLE TIMERS Eight independent millisecond timers (0..7) can call GOSUB handlers. 15. BREAKPOINT MANAGER BREAK can set, list, delete and clear source-line breakpoints. BREAK 1000,2000 BREAK LIST BREAK DELETE 1000 BREAK CLEAR 16. VARIABLE WATCHING AND INTROSPECTION TRACE can watch scalar values while the program runs. VARINFO and ARRAYINFO can list variables, arrays, types, sizes, values and addresses. 17. SOURCE DEVELOPMENT TOOLS FIND supports ranges, WORD matching and FIND NEXT/PREV. REPLACE can perform literal replacement or safe identifier renaming. XREF finds symbol and line references, AUDIT checks common structural/source mistakes, and PROFILE measures executed lines. FIND "LOADBMP",1000-5000 FIND "PLAYERX",WORD FIND NEXT REPLACE "PLAYERX","SHIPX",WORD XREF SCORE AUDIT PROFILE ON PROFILE ON MARK 18. EXTENDED LIST / EDIT ERROR WORKFLOW LIST ERL and EDIT ERL jump directly to the last stored-program error line. LIST also supports paging and NOWAIT. 19. RECURSIVE / WIDE / PAGED DIRECTORY LISTING DIR is an alias for FILES and S, W and P options add recursion, wide output and paging. DIR "*.BAS",S,W,P 20. LCASE$ / UCASE$ ASCII case conversion functions are provided. 21. PLATFORM STARTUP / ARGUMENT FEATURES Windows provides COMMANDLINEARG$(n). The UEFI interpreter supports STARTUP.BAS and THOREAU.CFG. 22. SAFE WINDOWS MEMORY ACCESS Arbitrary PEEK/POKE-style access on Windows is guarded so invalid or protected addresses become BASIC errors instead of simply crashing the interpreter. 23. CATEGORIZED BUILT-IN HELP HELP and HELP name provide a built-in reference for the language and extensions. HELP uses the full physical text screen, wraps descriptions at word boundaries, and is independent of TXTWINDOW / VIEW PRINT while shown. 24. ON BREAK GOTO ESC/break events can be routed to a BASIC handler and resumed using the normal RESUME machinery. 25. LARGE MODERN BASIC MEMORY ARENA Variables, arrays, strings and loaded bitmaps use a modern 64-bit memory arena rather than the tiny segmented memory model of DOS BASIC. Strings are compacted automatically; ERASE and replaced bitmap slots return storage to a coalescing free list. Live arrays do not move, preserving VARPTR values, and FRE(0) includes reusable reclaimed blocks. 26. INTERNATIONAL UEFI KEYBOARD SUPPORT The UEFI build supports 23 DOS-style keyboard layout codes through THOREAU.CFG and the runtime KEYB command. Compatible USB HID boot keyboards can be read directly, bypassing incomplete firmware key translation. 27. HYPERCOMPLEX NUMBERS The @ suffix adds a native hypercomplex numeric type covering complex numbers, quaternions and octonions. Values participate directly in +, -, *, /, ^, = and <> expressions, may be stored in arrays, expose named components, and support transcendental functions including EXP, LOG, SIN, COS, TAN, SINH, COSH, TANH and principal square roots. Z@=CPLX(3,4) Q@=QUAT(1,2,3,4) O@=OCT(1,2,3,4,5,6,7,8) 28. MOUSE INPUT AND EVENTS Windows and UEFI share mouse position/button/wheel functions, MOUSE ON/OFF, MOUSEPOS and ON MOUSEMOVE / ON MOUSECLICK GOSUB handlers. UEFI provides its own software pointer over the framebuffer when a firmware pointer protocol is available. 29. SIMULTANEOUS HELD-KEY STATE KEYDOWN(key$) lets games test several currently held controls in one frame without consuming the INKEY$ event queue. KEYSTATEAVAILABLE tells portable programs whether the current keyboard backend can report key releases. 30. TCP/IP, DNS AND HTTP/HTTPS Eight TCP/IPv4 client slots, DNS lookup and HTTPGET$ provide ordinary BASIC access to network services on Windows and UEFI. NETINFO reports network backend, protocol availability, addressing and diagnostic state. On UEFI, a raw SNP fallback can supply Ethernet, ARP, DHCPv4, IPv4, UDP, DNS, TCP and plain HTTP when higher-level firmware network protocols are unavailable. 31. NATIVE x64 BYTECODE / JIT EXECUTION Stored BASIC programs can compile supported expressions, statements, loops and cross-line regions to native x64 code. The JIT covers ordinary scalar numeric work, native hypercomplex values, numeric/@ arrays, IF/ELSE, FOR/NEXT, WHILE/WEND, DEF FN and classic GOSUB/RETURN-heavy code. Unsupported constructs automatically fall back to the interpreter. JIT OFF provides a complete classic-interpreter path for compatibility and A/B testing. 32. PIXEL-EXACT GRAPHICS TEXT GPRINT draws the normal 8x16 character glyphs at any graphics coordinate, rather than only at LOCATE's character-cell positions. The optional background can be omitted for transparent labels over charts, games or images. GPRINT (37,29),"Chart title" GPRINT (37,49),"opaque",15,1 33. CROSS-PLATFORM CLIPBOARD CLIPBOARD writes text and CLIPBOARD$ reads it. Windows converts Thoreau's CP437 BASIC bytes to/from the desktop Unicode clipboard (CF_UNICODETEXT); UEFI keeps a byte-for-byte session-local clipboard because UEFI defines no global clipboard protocol. Unicode characters with no CP437 representation become '?' when read on Windows. CLIPBOARD "text from BASIC" A$=CLIPBOARD$ 34. DIAGNOSTIC TRAPPED-ERROR PRINTING GW-compatible ON ERROR handling is silent by default. OPTION ERRORPRINT 1 is a Thoreau diagnostic extension that also prints errors which are caught successfully by ON ERROR GOTO. 35. GENERAL MIDI / GS WAVETABLE SOUND Thoreau BASIC can play a complete sample-based GM instrument set directly through its own 48 kHz PCM engine. Programs are 0..127 and four drum kits are 128..131. The external sample bank is shared by Windows and UEFI and may use lossless TBGM3 or lossy Opus TBGM4 storage. Playback always uses PCM. SOUND PRELOAD SOUND ON INSTRUMENT 0,40 NOTE 0,60,100 NOTEOFF 0,60 36. ASYNCHRONOUS MIDI, WAV, FLAC AND OPUS PLAYBACK Standard MIDI Files and loaded WAV/FLAC/Opus audio can play while BASIC continues. MIDI uses the same Thoreau GM wavetable; WAV playback has its own 64-channel pool. LOADMID 0,"SONG.MID" PLAYMID 0 LOADWAV 0,"VOICE.WAV" PLAYWAV 0 37. MIDI CONTROLLERS AND EFFECTS MIDI playback includes supported GM/GS controller handling and built-in reverb, chorus and delay sends. MIDFX can force an all-part audition while MIDCCINFO exposes the live routing and wet-return meters. 38. PARALLEL SAMPLE-BANK LOADING SOUND PRELOAD can use up to eight decoders for TBGM3 lossless blocks or TBGM4 Opus samples. All audio is expanded before playback. SOUND INFO reports the actual worker count, load timing and fallback state. 39. FILE AND DIRECTORY ARRAYS GETFILES returns names with their original case in a string array, with an optional file mask and flags for files, directories and the parent. GETFILES ENTRIES$(),N,"*.TXT" 40. FRAMED SELECTION BOXES SELECTBOX provides keyboard/mouse selection, columns, display truncation, optional colors and single/double box-drawing frames. The selected result is an array index; Escape returns -1. 41. SELECTED-STATE RECOVERY AND VERIFIED FILE WRITES STATEWRITE / STATELOAD checkpoint an explicit variable schema to alternating sealed generations. FLUSH, FILECOMMIT, FILECOPY, FILECRC, SESSIONLOCK and ABORTFILES support applications which manage durable data and backups. 42. TEXT COUNTS AND SUPPORT INFORMATION TEXTSTATS counts an array range; CRC32 checks byte strings. SYSTEMINFO$ provides compact platform and runtime diagnostics; BATTERYPERCENT reports a reading when the OS or firmware exposes one. DIFFERENCES WITH GW-BASIC ========================= Thoreau BASIC aims for strong GW-BASIC source compatibility where the old behavior is useful and well-defined, but it is not a byte-for-byte clone. The following differences are deliberate in 3.2 rather than known bugs: 1. ARRAYS REQUIRE EXPLICIT DIM GW-BASIC implicitly dimensions an otherwise unknown array to an upper bound of 10 on first use. Thoreau requires DIM (or REDIM) before array access. This avoids silent accidental arrays and makes memory use explicit. GETFILES is an explicit exception: it creates/replaces its destination array. 2. NO SPACED GO TO / GO SUB SPELLINGS GW-BASIC accepts the historical two-word spellings GO TO and GO SUB and then normalizes them. Thoreau accepts GOTO and GOSUB only. 3. NO COMMA BEFORE THEN / ELSE Some early Microsoft BASIC grammar survived in GW-BASIC as forms such as IF X=5, THEN ... and IF X=5, GOTO 100, ELSE .... Thoreau deliberately does not accept those comma forms. 4. COMPUTED EXPLICIT GOTO / GOSUB ARE A THOREAU EXTENSION Thoreau allows: GOTO BASE+OFFSET GOSUB HANDLER+N*10 The expression is evaluated completely before branching. This extension does not apply to the compact IF ... THEN line form or to ON ... GOTO/GOSUB lists, which use literal line numbers to keep their grammar unambiguous. RENUM leaves computed targets untouched. 5. TRON IS EXECUTABLE AND MAY TAKE A RANGE Thoreau allows TRON and TROFF inside a stored program and extends TRON with an optional line/range filter: TRON 1000-2000 RENUM updates these ranges. 6. MODERN ADDRESS SPACE AND MACHINE FEATURES PEEK/POKE addresses, VARPTR, screen memory, networking, mouse input, sprites, JIT/PARFOR, clipboard, 24-bit color and other Thoreau extensions necessarily exceed the DOS memory and hardware model of GW-BASIC. Programs relying only on the classic subset can ignore these facilities. The built-in command HELP DIFFERENCES summarizes the principal intentional differences from the interactive prompt. INCLUDED SHOWCASE PROGRAMS -------------------------- The included examples exercise Thoreau's newer facilities rather than only document their syntax. MANDELZOOM.BAS A realtime scalar Mandelbrot explorer. Move the mouse to pan; hold the left button to zoom in or the right button to zoom out. R resets the view, C toggles mouse capture, and Q or Escape quits. Arrow keys and +/- also work. The top 16 pixel rows are reserved for a fixed-width FPS/scale display. Adaptive pixel blocks target approximately 30 FPS, so detail changes with the measured render time. This example has no native-complex mode toggle; the separate complex-demo below still demonstrates the language's @ type. SELECTOR.BAS Small demonstration of GETFILES/SELECTBOX. SpriteInvaders A compact Space-Invaders-style sprite demonstration. It shows loaded sprite images, multiple persistent instances, movement, transparent sprites, collision detection, projectiles, keyboard control and timed game loops. NeonDescent A more ambitious 1024x768 scrolling shooter inspired by classic vertically scrolling PC/Amiga shooters. A large bitmap is scrolled with BITBLT while ships, aliens, shots and bombs are handled by the sprite system. It demonstrates many simultaneous sprite instances, pixel-perfect collisions, HUD text over sprites, KEYREPEAT, WAITREL and continuous background motion. GorseGlass A 1024x768 analytic raytracer used as both a visual demo and a JIT stress test. It combines nested pixel loops, arrays, many GOSUB/RETURN calls, hard shadows, a checkerboard floor, reflective materials and a glass sphere with explicit entry/exit Snell refraction plus Schlick Fresnel blending. The included v2.5 file is the quality version retained after comparison against the faster simplified secondary-shading path. Island3D A first-person fractal-island renderer and PARFOR stress test. The distributed configuration renders a 640x480 view over a 1024x1024 heightfield (VOX=4) with shoreline shaping, distance fog, directional terrain lighting, trees and a double-buffered column renderer. Each screen column is an independent PARFOR iteration and writes to its own slice of the work buffer before one completed frame is presented with PUT. Start it with: RUN "ISLAND3D" Running controls are mouse-only, so the demo does not depend on USB HID KEYDOWN support once it has started: move mouse look / turn hold left button walk forward hold right button walk backward hold both buttons quit A mouse is required; the program checks MOUSEPRESENT before entering the main loop. OPTION PARTHREADS 0 lets Thoreau choose the worker count. Terrain density is controlled near the top of the program by VOX. The supplied VOX=4 gives a 1024x1024 heightfield; VOX=2 gives 512x512 and reduces ray-sampling density accordingly. The frame limiter is intentionally disabled for benchmarking: REM CAP=1 Remove REM from that line to enable the WAITREL 16 limiter. Leave it commented to see the uncapped FPS counter. complex-demo A 2D Mandelbrot renderer written using the new native complex syntax. Instead of manually carrying separate real and imaginary variables, the iteration can be written directly with @ values: C@=CPLX(CR,CI) Z@=CPLX(0,0) Z@=Z@*Z@+C@ The demo is a compact introduction to CPLX(), @ variables and complex arithmetic inside an ordinary BASIC graphics program. quaternion-demo A quaternion fractal demonstration using the 4-component QUAT() syntax. It renders a three-dimensional ray-marched slice of a four-dimensional quaternion Julia set, using iterations such as: Q@=QUAT(X,Y,Z,W) Q@=Q@*Q@+C@ The program combines quaternion arithmetic, NORM, LOG, ray marching, numerical surface normals and 24-bit graphics. It is deliberately a substantial example of the new mathematics rather than a syntax test. mouse-paint-demo A compact paint program using mouse position, buttons, wheel-controlled brush sizing and ON MOUSEMOVE / ON MOUSECLICK event handlers. video-modes-demo Enumerates physical/display modes with VIDEOMODES and VIDEOMODE and shows how SCREEN MODE selects one. iss-tracker A HTTP networking example. It reads the current International Space Station position from a public API and plots it on WORLDMAP.BMP, leaving an orbital trail behind the moving position. DATA TYPES ---------- Suffix Type ------ ---- % 16-bit integer & 32-bit integer && 64-bit integer ! single-precision floating point # double-precision floating point $ string @ hypercomplex (complex / quaternion / octonion) DEFI64 adds a native 64-bit integer default type. Integer literals and memory addresses can use the full 64-bit range supported by the interpreter. DEFINT, DEFLNG, DEFI64, DEFSNG, DEFDBL and DEFSTR also determine the resolved type of an unsuffixed name. When the resolved type matches an explicit suffix, the two spellings are aliases for the same variable, as in GW-BASIC: DEFINT I-N : I=42 : PRINT I% DEFDBL R-T : R#=3.5 : PRINT R A suffix that explicitly requests another type still creates a distinct name. HYPERCOMPLEX NUMBERS -------------------- Thoreau BASIC treats complex numbers, quaternions and octonions as one native @ type. The value carries its current dimension internally: complex 2 components real, i quaternion 4 components real, i, j, k octonion 8 components real, e1, e2, e3, e4, e5, e6, e7 Constructors: Z@=CPLX(3,4) Q@=QUAT(1,2,3,4) O@=OCT(1,2,3,4,5,6,7,8) A plain real number mixed with an @ value is promoted automatically. Promotion follows the Cayley-Dickson tower: real -> complex -> quaternion -> octonion The wider operand determines the result dimension. For example: Z@=CPLX(10,20) Q@=QUAT(1,2,3,4) PRINT Q@+Z@ The complex value is embedded as (10,20,0,0) before quaternion addition. Assigning an ordinary real number to an @ variable creates a complex value with zero imaginary part: A@=5 ' equivalent to CPLX(5,0) @ arrays are ordinary BASIC arrays: DIM Z@(100) DIM Q@(20,20) Z@(10)=CPLX(2,3) COMPONENT ACCESS Named components may be read directly: Z@.R real component Z@.I complex i Q@.R Q@.I Q@.J Q@.K O@.R O@.E1 O@.E2 ... O@.E7 For convenience, .I is the same component as .E1, .J as .E2, and .K as .E3. Array elements and parenthesized hypercomplex expressions may also use the postfix: PRINT Q@(5).K PRINT (A@*B@).E7 PRINT CONJ(Q@).I Reading a component above the value's current dimension returns zero. Assigning such a component promotes the value automatically: A@=CPLX(1,2) A@.K=3 A@ is now a quaternion, equivalent to QUAT(1,2,0,3). COMP(x,n) is the expression-friendly alternative and returns component 0..7. Component 0 is always the real/scalar component: PRINT COMP(A@*B@,3) ARITHMETIC The operators +, -, * and / work directly on @ values. Addition/subtraction are componentwise. Multiplication uses the standard Cayley-Dickson construction with the quaternion convention: i*j = k j*k = i k*i = j Quaternion multiplication is not commutative: I@=QUAT(0,1,0,0) J@=QUAT(0,0,1,0) PRINT I@*J@ ' +k PRINT J@*I@ ' -k Octonion multiplication is neither commutative nor associative. Thoreau uses the language's normal left-associative evaluation, so: A@*B@*C@ means: (A@*B@)*C@ For octonions, A@*(B@*C@) may genuinely produce a different result. This is a property of octonion algebra, not a rounding or parser error. Division is defined explicitly as: A@ / B@ = A@ * INV(B@) Division by a zero-norm value reports Division by zero. FUNCTIONS CONJ(x) conjugate; negate every non-real component INV(x) multiplicative inverse ABS(x) Euclidean magnitude NORM(x) Euclidean magnitude; same result as ABS for @ values NORM2(x) squared Euclidean norm COMP(x,n) component 0..7 Examples: Z@=CPLX(3,4) PRINT ABS(Z@) ' 5 PRINT NORM2(Z@) ' 25 PRINT CONJ(Z@) PRINT Z@*INV(Z@) ' unit value COMPARISON AND OUTPUT = and <> compare all promoted components exactly. Hypercomplex values have no natural ordering, so <, >, <= and >= report Illegal comparison. PRINT and STR$ use a canonical component form and keep the current dimension visible, for example: 3+4i 1+2i+3j+4k 1+2e1+3e2+4e3+5e4+6e5+7e6+8e7 Every component is printed, including zero components. Hypercomplex values are stored internally with double-precision components. TRANSCENDENTAL FUNCTIONS AND POWERS The one-value functions EXP, LOG, SIN, COS, TAN, SINH, COSH, TANH and square root work on complex numbers, quaternions and octonions. SQR and SQRT are equivalent square-root spellings. Ordinary scalar arguments continue to use their traditional real-number behavior. For an @ value x, write x = a + v where a is the real component and v is the vector formed by all non-real components. Let r=|v|. When r is nonzero, u=v/r is the unit imaginary direction carried by x itself. Because the subalgebra generated by one complex/quaternion/octonion value is associative, the same closed forms work for all three dimensions. In particular: EXP(a+v) = exp(a) * (cos(r) + u*sin(r)) SIN(a+v) = sin(a)*cosh(r) + u*cos(a)*sinh(r) COS(a+v) = cos(a)*cosh(r) - u*sin(a)*sinh(r) SINH(a+v) = sinh(a)*cos(r) + u*cosh(a)*sin(r) COSH(a+v) = cosh(a)*cos(r) + u*sinh(a)*sin(r) TAN(x) is SIN(x)/COS(x), and TANH(x) is SINH(x)/COSH(x). A zero denominator reports Division by zero. Large real or vector components can overflow the underlying double-precision exponential/hyperbolic calculations; Thoreau reports Overflow rather than silently returning an invalid @ value. LOG AND PRINCIPAL VALUES LOG is multivalued for complex numbers and even more so for quaternions and octonions. Thoreau therefore defines one deterministic principal value. For a non-real x=a+v: LOG(x) = log(|x|) + u*atan2(|v|,a) For positive real @ values the imaginary part is zero. For a negative real complex value the principal direction is +i, matching the usual complex principal logarithm. A negative real quaternion also chooses +i, while a negative real octonion chooses +e1. These are conventions: infinitely many other quaternion/octonion logarithms are mathematically valid. LOG of a zero @ value, for example LOG(CPLX(0,0)), reports Illegal function call. The same convention determines principal square roots: SQRT(x) = SQR(x) = EXP(.5*LOG(x)) with zero handled directly. Thus: PRINT SQRT(CPLX(-1,0)) PRINT SQRT(QUAT(-1,0,0,0)) PRINT SQRT(OCT(-1,0,0,0,0,0,0,0)) select +i for the complex/quaternion results and +e1 for the octonion result. Other roots exist; Thoreau deliberately returns one repeatable principal root. POWER OPERATOR The exponent of an @ value must be an ordinary real scalar: Q@^2 Q@^-3 O@^.5 Integer exponents are evaluated by exponentiation by squaring. This is unambiguous even for octonions because the Cayley-Dickson algebras used here are power-associative: powers of one value have a well-defined meaning. Negative integer exponents use INV(x). Non-integer real powers use the principal definition: x^p = EXP(p*LOG(x)) so they inherit the LOG branch convention described above. Zero to a positive real power is zero; zero to a negative power reports Division by zero. A hypercomplex exponent is intentionally not accepted: A@^B@ ' Type mismatch For quaternions, EXP(B@*LOG(A@)) and EXP(LOG(A@)*B@) need not agree because multiplication is non-commutative. Octonions additionally make parenthesization significant. Thoreau does not choose one of those inequivalent definitions silently. IDENTITIES AND QUIRKS Functions of a single @ value are well defined under the rules above, but many familiar multi-value identities require commuting operands. For example, with independent quaternion or octonion values A@ and B@, users must not generally assume: EXP(A@+B@) = EXP(A@)*EXP(B@) or ordinary trigonometric addition formulas. Octonion multiplication remains non-associative, so explicit parentheses can change expressions involving several independently oriented values. This is mathematical behavior, not an interpreter quirk. Examples: Z@=CPLX(0,1) PRINT EXP(Z@) PRINT SIN(Z@) PRINT COS(Z@) Q@=QUAT(1,2,3,4) PRINT EXP(LOG(Q@)) PRINT Q@^2 PRINT Q@^.5 O@=OCT(-1,0,0,0,0,0,0,0) PRINT SQRT(O@) ' principal +e1 root WRITE#/INPUT# do not define a portable textual @ serialization; use STR$ or store components explicitly when a file representation is needed. ERROR HANDLING -------------- ON ERROR GOTO 9000 ... 9000 PRINT "ERROR";ERR;"AT";ERL 9010 RESUME NEXT Runtime errors print their message and source line, for example: Illegal function call in 1230 ON BREAK GOTO can trap ESC/break events. RESUME, RESUME NEXT and RESUME line leave an active error/break handler correctly. PROGRAMMABLE TIMERS ------------------- Eight independent timers are available, numbered 0 through 7. TIMER(0)=1000 ON TIMER(0) GOSUB 9000 TIMER(0) ON Intervals are milliseconds. Timers are non-preemptive and are dispatched between BASIC statements. RELATIVE FRAME PACING --------------------- WAITREL is intended for game loops, animation and other code that needs a stable frame period without manually subtracting TIMER values: WAITREL milliseconds The first WAITREL establishes the reference point and waits the requested interval. Later calls wait only for the time still remaining since the previous WAITREL returned. Code executed between calls therefore counts toward the interval. For example: 100 GOSUB 1000 110 WAITREL 16 120 GOTO 100 If the game logic in GOSUB 1000 takes 5 ms, WAITREL waits roughly another 11 ms. If a frame already took 20 ms, WAITREL 16 returns immediately and re-anchors to the current time. It deliberately does not generate catch-up frames. WAITREL 0 can be used to reset the reference without a delay. WAITREL uses the platform's monotonic high-resolution timing. On modern Windows it uses a high-resolution waitable timer when available; on older Windows it yields while waiting rather than inheriting the coarse desktop Sleep() interval. On UEFI it uses short firmware Stall() intervals. ESC and ON BREAK GOTO remain responsive while WAITREL is waiting. UEFI INTERNATIONAL KEYBOARD SUPPORT =================================== This section applies only to the x64 UEFI build. Windows uses the normal Windows keyboard input and does not use THOREAU.CFG or KEYB layout translation. At startup, Thoreau looks for THOREAU.CFG in the directory containing the EFI. A keyboard layout is selected with a DOS-style line such as: KEYB GR If THOREAU.CFG is absent, the default is US. Blank lines and lines beginning with ;, # or REM are ignored. An unknown KEYB code falls back to US at startup. The active layout can be displayed or changed immediately from BASIC: KEYB KEYB GR KEYB UK KEYB US A runtime KEYB change affects only the current session and does not rewrite THOREAU.CFG. An unknown runtime code leaves the current layout unchanged. Supported layouts: Code Layout Code page ---- ----------------------------- --------- BE Belgium 850 BR Brazil 850 DK Denmark 850 GR Germany 850 SU Finland 850 FR France 850 UK United Kingdom 850 IT Italy 850 YU Yugoslavia 852 CF Canadian French 850 LA Latin America 850 NL Netherlands 850 NO Norway 850 PL Poland 852 PO Portugal 850 SV Sweden 850 SG Swiss German 850 SF Swiss French 850 SP Spain 850 SL Slovak 852 CZ Czech 852 HU Hungary 852 US USA 437 On a compatible USB HID boot keyboard, Thoreau can read raw HID reports and translate physical key usages itself. This avoids firmware errors involving international keys, including the ISO 102nd key used for <, > and | on several European layouts. Raw USB HID is preferred, but it cannot be assumed on every UEFI machine. An internal laptop keyboard, PS/2-style keyboard, Bluetooth keyboard, firmware- managed keyboard controller, or a USB keyboard whose EFI_USB_IO_PROTOCOL device cannot be safely taken over may be available only through the generic UEFI text input interface. Rather than make Thoreau unusable on such systems, it falls back to firmware keyboard input. The active backend is shown at startup. Typical status lines are: Keyboard: GR (CP850, USB HID) Keyboard: GR (CP850, firmware) The difference has practical consequences. Raw USB HID exposes physical key usages and key-release state, so Thoreau can distinguish international physical keys accurately, apply its own KEYB layout translation and implement independent KEYREPEAT timing. Firmware input has already been interpreted by the firmware and does not provide reliable key-release events. Thoreau can still apply the selected layout as far as the received key information allows, but it cannot recover a physical key the firmware never reports. In particular, a firmware that collapses or omits the ISO 102nd key cannot be repaired by software above that interface. For the same reason, KEYREPEAT delay/rate control is available on raw USB HID UEFI input but not on firmware fallback. In firmware mode the firmware owns repeat timing. The fallback is therefore a compatibility path, not the preferred keyboard backend: it keeps more machines usable at the cost of less complete physical-key information and no independent key-up/repeat control. INKEY$ EXTENDED KEYS ==================== This section applies to both Windows and UEFI. INKEY$ returns an empty string when no key is waiting and a one-character string for ordinary character keys. Supported extended keys use the classic Microsoft BASIC/DOS two-byte form: CHR$(0)+CHR$(scan) The scan values are: Key Scan Key Scan --------- ---- --------- ---- F1 59 F6 64 F2 60 F7 65 F3 61 F8 66 F4 62 F9 67 F5 63 F10 68 Home 71 Up 72 Page Up 73 Left 75 Right 77 End 79 Down 80 Page Down 81 Insert 82 Delete 83 For example: K$=INKEY$ IF K$=CHR$(0)+CHR$(72) THEN PRINT "UP" IF K$=CHR$(0)+CHR$(80) THEN PRINT "DOWN" IF K$=CHR$(0)+CHR$(75) THEN PRINT "LEFT" IF K$=CHR$(0)+CHR$(77) THEN PRINT "RIGHT" This makes old BASIC games that test DOS/GW-BASIC extended-key strings portable between the Windows and UEFI builds. INPUT$ RAW KEYBOARD INPUT ========================= Without a file number, INPUT$(count) waits until exactly count keyboard characters have been collected. It does not echo them and does not require Enter. This makes it useful when a program wants to block for raw keystrokes rather than poll with INKEY$. For example: K$=INPUT$(1) PRINT ASC(K$) Printable characters return their BASIC byte. TAB is CHR$(9), Enter is CHR$(13) and ESC is CHR$(27). Control characters are not filtered merely because they are non-printing. On Windows, F10 is handled by Thoreau rather than activating the window system menu. There is one important difference from INKEY$ for extended keys. INKEY$ exposes the classic two-byte CHR$(0)+CHR$(scan) sequence. Keyboard INPUT$ returns CHR$(0) for an extended navigation/function event, matching the GW-BASIC INPUT$ convention used by legacy software. KEYDOWN remains the independent held-state interface. With a file number, INPUT$(count,#n) reads exactly count bytes from the file (up to end-of-file) rather than using keyboard semantics. KEY REPEAT FOR GAMES ==================== KEYREPEAT can override the usual typematic delay: KEYREPEAT delayMilliseconds,rateHz KEYREPEAT DEFAULT For example: KEYREPEAT 0,30 The initial key press is delivered immediately. With a delay of 0, the first repeat follows after one normal repeat interval, so 0,30 feels continuous for game movement instead of waiting through the desktop keyboard-repeat delay. On Windows, custom KEYREPEAT timing is generated by Thoreau from key-down and key-up state and does not depend on the Windows user repeat setting. DEFAULT returns control to the normal Windows typematic setting. On UEFI with direct raw USB HID keyboard input, Thoreau also has key-up state and uses the requested timing. The UEFI firmware text-input fallback does not expose key-up state, so firmware repeat timing cannot be overridden there. KEYREPEAT DEFAULT restores the raw-HID default of approximately 500 ms at 30 repeats per second. SIMULTANEOUS KEY STATE ---------------------- INKEY$ remains the classic nonblocking key-event queue. For action games, 2.4 also provides held-state queries that do not remove anything from that queue: IF KEYDOWN("LEFT") THEN X=X-4 IF KEYDOWN("RIGHT") THEN X=X+4 IF KEYDOWN("SPACE") THEN GOSUB 9000 All three tests are independent, so LEFT+SPACE can move and fire in one frame. KEYDOWN accepts single characters, common names such as LEFT, RIGHT, UP, DOWN, SPACE, ENTER, ESC, SHIFT, CTRL, ALT and F1..F12, and classic two-byte extended keys such as CHR$(0)+CHR$(75). KEYSTATEAVAILABLE KEYSTATEAVAILABLE() returns -1 when real held-key state is available. Windows provides it while the Thoreau window is active. On UEFI it requires the raw USB HID backend, whose boot-keyboard report can represent up to six ordinary simultaneous keys plus modifier keys. Firmware text input has no reliable key-release information, so KEYSTATEAVAILABLE returns 0 there. When RUN or CONT returns to Ready, version 2.5.2 discards queued gameplay key events and interpreter-owned repeat state on both platforms. This does not change KEYDOWN while the program is running; it prevents old movement/fire keys from being consumed later by the editor, INKEY$, INPUT$ or LIST paging. MOUSE INPUT AND EVENTS ---------------------- Mouse state uses physical framebuffer coordinates on both platforms: MOUSE ON MOUSEPOS 320,240 X=MOUSEX() Y=MOUSEY() B=MOUSEB() W=MOUSEWHEEL() PRINT MOUSEPRESENT MOUSEB uses bit 0 for left, bit 1 for right and bit 2 for middle where the platform exposes it. MOUSEWHEEL is cumulative and signed. MOUSE ON/OFF controls pointer visibility; state functions remain safe if no mouse is present. Windows uses the native window pointer and translates scaled/letterboxed window coordinates back to BASIC framebuffer coordinates. UEFI prefers EFI_SIMPLE_POINTER_PROTOCOL and falls back to EFI_ABSOLUTE_POINTER_PROTOCOL. It draws a 12x18 black/white pointer after the BASIC framebuffer and sprite layers, so pointer movement does not burn trails into program graphics. Mouse events use ordinary non-preemptive GOSUB handlers: ON MOUSEMOVE GOSUB 9000 ON MOUSECLICK GOSUB 9100 ON MOUSEDOUBLECLICK GOSUB 9200 They dispatch between BASIC statements, like programmable timers. Movement is coalesced and dispatched at up to about 200 Hz. MOUSECLICK fires on a button-down edge. MOUSEDOUBLECLICK (alias MOUSEDBLCLICK) recognizes two clicks of the same button within 500 ms and 16 pixels. Inside click/double-click handlers MOUSEX(), MOUSEY() and MOUSEB() expose the captured event snapshot. A handler line of 0 disables the event. On UEFI pointer protocols are polled on a roughly 5 ms cadence while a program is running. VIDEO MODES AND LOGICAL FRAMEBUFFERS ------------------------------------ Windows and UEFI expose the same discovery syntax: SCREEN MODES N=VIDEOMODES() VIDEOMODE index,widthVar,heightVar SCREEN MODE index On UEFI these are real GOP modes. SCREEN width,height finds an exact matching GOP resolution, and SCREEN MODE selects the indexed GOP mode. Windows uses a logical BASIC framebuffer instead of switching the Windows desktop mode. SCREEN width,height accepts arbitrary sane raster sizes from 8x16 through 8192x8192, with a 64-million-pixel cap. If the requested framebuffer is larger than the available work area, the window is scaled down while preserving aspect ratio. F11 fullscreen scales the same framebuffer to the monitor and uses black bars for unused space. VIDEOMODES returns the unique physical resolutions reported by the monitor containing the Thoreau window; SCREEN MODE uses one of those dimensions for the logical framebuffer. TCP/IP, DNS AND HTTP/HTTPS -------------------------- Thoreau 2.4 provides a common IPv4 client API on Windows and UEFI. Eight TCP slots are available, numbered 0 through 7: TCP OPEN 0,"example.com",80 TCP SEND 0,"GET / HTTP/1.0"+CHR$(13)+CHR$(10)+CHR$(13)+CHR$(10) A$=TCPRECV$(0) TCP CLOSE 0 TCP TIMEOUT 15000 PRINT TCPCONNECTED(0) PRINT TCPEOF(0) PRINT DNS$("example.com") PRINT NETPRESENT() NETINFO NETINFO is a diagnostic command. It displays the active network backend and the most recent network error. On UEFI it also reports availability of SNP, PXE, Managed Network, DHCP4, IP4, UDP4, DNS4, TCP4, HTTP and TLS; raw-SNP readiness; and the current IP address, subnet mask, gateway and DNS server when known. This is useful both for programs being developed against the network API and for diagnosing firmware whose high-level network services are incomplete. HTTP and HTTPS requests are available without manually constructing HTTP text: J$=HTTPGET$("https://example.com/") PRINT HTTPSTATUS() PRINT NETERROR$() Optional request headers are supplied as CR/LF-separated Name: value lines: H$="Accept: application/json"+CHR$(13)+CHR$(10) J$=HTTPGET$(URL$,H$) HTTPGET$ returns the response body and accepts bodies up to 1 MiB. Ordinary network failures do not raise a BASIC runtime error; the call returns an empty result where appropriate and NETERROR$ describes the most recent network error. Syntax/type errors remain normal BASIC errors. Windows implements raw networking with Winsock and HTTP/HTTPS with WinHTTP. UEFI first uses the standard EFI_DNS4_PROTOCOL, EFI_TCP4_PROTOCOL and EFI_HTTP_PROTOCOL service bindings where they work. If those higher-level services are absent or unusable but EFI_SIMPLE_NETWORK_PROTOCOL is available, Thoreau can fall back to its internal raw network stack: Ethernet -> ARP -> DHCPv4 -> IPv4 -> UDP -> DNS -> TCP -> plain HTTP The raw path acquires IPv4 configuration with DHCPv4 and supplies the DNS and TCP operations used by the common BASIC API. HTTPS is not implemented by the raw stack; it continues to depend on the firmware HTTP/TLS implementation. NETINFO shows which firmware protocols were found, whether raw SNP is ready, the active backend, current IP/subnet/gateway/DNS values and the last network error. Network features remain optional on UEFI; NETPRESENT() can be used before a program assumes that a usable IPv4 stack is available. NUMERIC LITERALS ================ Decimal numbers use the normal BASIC forms. Thoreau also accepts classic Microsoft BASIC hexadecimal and octal prefixes anywhere a numeric literal is valid: &HFF hexadecimal 255 &O377 octal 255 &O10 octal 8 The H and O prefixes are case-insensitive. 24-BIT GW-BASIC GRAPHICS ======================== Thoreau BASIC keeps the classic GW-BASIC graphics model, but the drawing surface is a modern 24-bit RGB framebuffer. COLOR VALUES ------------ Most graphics commands accept the traditional palette numbers 0 through 15. Those map to the 16 CGA-style colors. They also accept a packed 24-bit RGB value: &HRRGGBB Examples: &HFF0000 red &H00FF00 green &H0000FF blue &HFF8800 orange &H202020 dark gray Internally the low 24 bits are used as 0xRRGGBB. A non-negative color value greater than 15 is interpreted as a direct RGB color. Several commands also accept three separate RGB components, each 0 through 255: red,green,blue For example, these two commands draw the same color: PSET (100,100),&HFF8800 PSET (100,100),255,136,0 PSET / PRESET ------------- Classic forms: PSET [STEP](x,y)[,color] PRESET [STEP](x,y)[,color] Thoreau 24-bit forms: PSET [STEP](x,y),r,g,b PRESET [STEP](x,y),r,g,b Examples: PSET (100,80),&H40C0FF PSET (100,80),64,192,255 PRESET STEP(10,0),255,0,0 If the color is omitted, PSET uses the current foreground color and PRESET uses the current background color. Both update the GW-BASIC "last point referenced", so STEP coordinates and LINE -(x,y) retain classic behavior. GPRINT ------ GPRINT places the normal 8x16 text glyphs at an exact graphics coordinate: GPRINT [STEP](x,y),text$[,fg[,bg]] Unlike LOCATE/PRINT, x and y are not character-cell coordinates. With no active WINDOW they are framebuffer pixels, so a label can begin at pixel 37 rather than being forced onto an 8-pixel text column. STEP and the normal VIEW/WINDOW mapping are honored. If fg is omitted, GPRINT uses the current foreground color. If bg is omitted, the glyph background is transparent and only lit character pixels are drawn. Supplying bg paints the complete 8x16 cell first: GPRINT (37,29),"Chart title" GPRINT (37,49),"Opaque label",&HFFFFFF,&H202020 GPRINT does not move the normal text cursor used by LOCATE and PRINT. LINE ---- Classic geometry and B/BF box flags are retained: LINE [[STEP](x1,y1)]-[STEP](x2,y2)[,color][,B|BF] The color may be a palette number, a packed 24-bit value, or an RGB triple: LINE (10,10)-(300,150),&HFF8800 LINE (10,10)-(300,150),255,136,0 LINE (10,10)-(300,150),255,136,0,B LINE (10,10)-(300,150),30,80,160,BF B draws a box and BF draws a filled box. If the first point is omitted, LINE starts from the last point referenced: PSET (20,20) LINE -(200,100),&H00FF80 STEP on the second point is relative to the first point of that LINE. CIRCLE ------ CIRCLE [STEP](x,y),radius[,color[,start[,end[,aspect]]]] CIRCLE accepts a palette color or one packed 24-bit RGB value: CIRCLE (320,240),100,&HFF8800 The GW-BASIC start, end and aspect arguments are accepted by the parser so older source continues to load, but in Thoreau BASIC 2.3 they are currently ignored. CIRCLE therefore draws a complete circle rather than arcs or ellipses. PAINT ----- PAINT [STEP](x,y)[,paint[,border]] The paint color accepts a palette/direct color or an RGB triple: PAINT (100,100),&H204080 PAINT (100,100),32,64,128 An optional border color follows. The border is one palette/direct packed color value: PAINT (100,100),32,64,128,&HFFFFFF The fill is a four-connected scanline flood fill. If border is omitted, the paint color is also used as the border color, matching the GW-BASIC default. POLYFILL -------- POLYFILL (x1,y1),(x2,y2),(x3,y3)[,...][,color] POLYFILL (x1,y1),(x2,y2),(x3,y3)[,...],r,g,b POLYFILL fills a polygon directly using the even-odd scanline rule. Concave polygons are supported, and up to 4096 vertices may be supplied. STEP on a vertex makes it relative to the preceding vertex. The color accepts palette values, packed 24-bit RGB, or separate RGB components. If color is omitted, the current foreground color is used. Examples: POLYFILL (20,20),(180,40),(130,160),(40,120),&HFF8800 POLYFILL (20,20),(180,40),(130,160),(40,120),255,136,0 COLOR ----- COLOR controls the current foreground/background colors used by text and by graphics commands whose color is omitted. Traditional forms: COLOR fg COLOR fg,bg COLOR ,bg Both fg and bg may be palette numbers or packed 24-bit colors: COLOR &H80FF40,&H101810 Thoreau also accepts RGB triples: COLOR r,g,b COLOR r,g,b,background_r,background_g,background_b Examples: COLOR 255,136,0 COLOR 255,136,0,16,16,16 Named text windows can have their own colors: COLOR @1,255,255,0,0,0,64 POINT ----- POINT(x,y) POINT reads the framebuffer pixel. For compatibility, if the pixel exactly matches one of the 16 standard palette entries, POINT returns the palette index 0 through 15. Otherwise it returns the raw packed 24-bit RGB value. Example: PSET (10,10),255,136,0 PRINT HEX$(POINT(10,10)) prints: FF8800 POINT returns -1 outside the screen or outside the active graphics VIEW. GET / PUT --------- The classic sprite/image commands operate on full 24-bit pixels: GET [STEP](x1,y1)-[STEP](x2,y2),array PUT [STEP](x,y),array[,PSET|PRESET|XOR|AND|OR] GET stores an 8-byte width/height header followed by one 32-bit value per pixel; the low 24 bits contain 0xRRGGBB. The numeric array must therefore provide at least: 8 + 4 * width * height bytes of storage. Example for a 64x64 image using a LONG array and OPTION BASE 0: OPTION BASE 0 DIM SPR&(4097) GET (0,0)-(63,63),SPR& PUT (200,100),SPR&,PSET PUT supports PSET, PRESET, XOR, AND and OR. XOR is the default, as in GW-BASIC. All operations are masked to 24 bits. GET and PUT require the entire rectangle to fit on screen; an out-of-bounds rectangle raises Illegal function call. PSET, LINE, CIRCLE and PAINT instead clip silently at the screen/VIEW boundary. DRAW ---- Thoreau implements the GW-BASIC Graphics Macro Language commands: U D L R E F G H M B N A TA C S P Ppaint,border flood-fills at the current DRAW position using the same engine as PAINT. Both values use DRAW numeric syntax, including =variable; substitution. The C command uses the same color resolver as the other graphics commands: 0 through 15 are palette colors, while larger values are packed RGB. Inside DRAW strings, numeric values are decimal or may be taken from a BASIC variable with =name; syntax. This is convenient for hexadecimal RGB values: COL&&=&HFF8800 DRAW "C=COL&&;R80D40L80U40" WINDOW / VIEW / SCREEN ---------------------- GW-BASIC logical graphics coordinates are supported: WINDOW (x1,y1)-(x2,y2) WINDOW SCREEN (x1,y1)-(x2,y2) Without SCREEN, Y increases upward in logical coordinates. With SCREEN, Y increases downward. WINDOW affects coordinate mapping; it is not a display page selector. VIEW defines a physical graphics clipping rectangle: VIEW [SCREEN] (x1,y1)-(x2,y2)[,fill[,border]] VIEW fill and border accept palette numbers or packed 24-bit colors: VIEW SCREEN (0,0)-(639,479),&H101820,&HFFFFFF SCREEN selects a graphics mode by dimensions rather than by an old DOS mode number: SCREEN 640,480 SCREEN 800,600 SCREEN 1024,768 The requested dimensions must correspond to a mode supported by the platform. BITMAP GRAPHICS --------------- In addition to the extended GW-BASIC-style drawing commands: LOADBMP slot,file$ BITBLT slot,x,y[,keyColor] BITBLT slot,(x,y)[,keyColor] SAVEBMP file$ [,(x1,y1)-(x2,y2)] LOADBMP reads an uncompressed 24-bit or 32-bit Windows BMP into a bitmap slot from 0 through 65535. BITBLT draws the loaded bitmap at the requested physical framebuffer position and clips it to the screen. The destination can be written as flat x,y parameters or as a parenthesized (x,y) point. With keyColor, source pixels matching the low 24 bits of that 0xRRGGBB value are transparent. SAVEBMP writes an uncompressed 24-bit BMP. With no rectangle it saves the active graphics VIEW, or the full graphics screen when no VIEW is active. An explicit (x1,y1)-(x2,y2) rectangle saves exactly that framebuffer region. Examples: LOADBMP 0,"PICS\FOREST.BMP" BITBLT 0,(0,0) BITBLT 0,(100,80),&HFF00FF SAVEBMP "SCREEN.BMP" SAVEBMP "PART.BMP",(100,80)-(399,279) Bitmap pixels are allocated from BASIC data memory and count against FRE. Replacing a loaded slot reclaims its previous pixel block. CLEAR, NEW, RUN or LOAD reclaim all loaded bitmap slots. Bitmap-slot introspection is available without drawing the image: BMPLOADED(slot) -1 if loaded, otherwise 0 BMPWIDTH(slot) pixel width, or 0 if not loaded BMPHEIGHT(slot) pixel height, or 0 if not loaded There is deliberately no BMPKEYCOLOR(): LOADBMP does not store one. BITBLT's optional transparent key belongs to that individual draw operation. LOADBMP/BITBLT is intended for external image assets, SAVEBMP writes framebuffer regions to disk, and GET/PUT captures and restores framebuffer regions in BASIC arrays. SOFTWARE SPRITES ---------------- Sprites use two kinds of slots: image slots 0..65535 loaded pixel data + opacity mask instance slots 0..65535 image reference, position and visibility This separation means one loaded image can be drawn as any number of independent instances without loading or storing the pixel data repeatedly. Load a sprite image: LOADSPRITE image,file$[,transparentColor] Examples: LOADSPRITE 0,"SPRITES\ALIEN.BMP",&HFF00FF LOADSPRITE 1,"SPRITES\SHIP.BMP",&HFF00FF The BMP may be larger than the current screen; drawing is clipped. The practical limit is BASIC memory. LOADSPRITE accepts the same uncompressed 24-bit and 32-bit BMP forms as LOADBMP, with the same 8192-pixel per-side safety limit. If transparentColor is omitted, every source pixel is opaque. Create one or more instances from the same image: SPRITE 0,0,(100,80) SPRITE 1,0,(200,80) SPRITE 2,0,(300,80) The flat coordinate form is accepted too: SPRITE 3,0,400,80 All four instances share image slot 0. SPRITE creates/reassigns the instance and makes it visible. Move or control instances: MOVESPRITE 1,(210,90) MOVESPRITE 1,210,90 HIDESPRITE 2 SHOWSPRITE 2 DELSPRITE 3 MOVESPRITE restores the old background and redraws the affected sprite layer, so moving instances do not leave trails. DELSPRITE removes only the instance; the shared image remains loaded and may still be used by other instances. Remove every active instance at once: SPRITEOFF SPRITEOFF deletes all sprite instances but deliberately keeps the loaded sprite images and their opacity masks. New instances can therefore be created again with SPRITE without reloading the BMP files. Coordinates are physical framebuffer pixels and are not transformed by WINDOW. Negative/off-screen positions are valid; visible portions are clipped. Instance position functions: X=SPRITEX(1) Y=SPRITEY(1) Loaded sprite-image slots can also be inspected: SPRITELOADED(image) -1 if loaded, otherwise 0 SPRITEWIDTH(image) pixel width, or 0 if not loaded SPRITEHEIGHT(image) pixel height, or 0 if not loaded SPRITEKEYCOLOR(image) stored transparency key, or -1 if none/unloaded Pixel-perfect collision: IF SPRITECOLLIDE(0,1) THEN PRINT "HIT" SPRITECOLLIDE returns -1 only when both instances exist, are visible, their rectangles overlap, and at least one pair of opaque source pixels occupies the same position. Hidden instances never collide. A fast rectangle test is done first; only the overlap area is examined pixel-by-pixel. When a transparency color is supplied to LOADSPRITE, Thoreau builds a compact 1-bit opacity mask once while loading the image. Every instance sharing that image also shares its mask. For a 32x32 image the collision mask is only 128 bytes. Text/sprite layering is selectable: SPRITETEXT UNDER SPRITETEXT OVER UNDER is the default and keeps the original behavior: sprite pixels appear over normal text. OVER redraws text foreground pixels after sprite compositing, so HUD text remains visible above moving sprites. Text-cell background pixels are not made into an opaque top layer; if a solid HUD panel is wanted, draw its background explicitly with the normal graphics commands. Sprite images use the BASIC DATA arena and count against FRE(0). Re-loading an image slot returns its old pixel and mask storage to the reusable allocator. CLEAR, NEW, RUN and LOAD discard all sprite images and instances together. STATEMENT SEPARATORS AND SINGLE-LINE IF ======================================= As in GW-BASIC, independent statements on one physical program line must be separated by a colon: A=1:PRINT A:CLS Thoreau 2.5.3 no longer accepts the permissive form A=1 PRINT A CLS. IF requires THEN except for the classic IF condition GOTO line spelling. A literal line number may follow THEN or ELSE directly; expressions are accepted only after an explicit GOTO/GOSUB command. LANGUAGE REFERENCE ================== PROGRAM EDITING / EXECUTION --------------------------- AUTO Syntax: AUTO [start][,increment] Does: automatic line numbers; existing lines are marked with * and an immediate Enter preserves the existing line Example: AUTO 1000,10 CHAIN Syntax: CHAIN [MERGE] file$[,[line][,[ALL][,DELETE range]]] Does: load/overlay another program; COMMON controls transferred variables Example: CHAIN MERGE "PART2.BAS",2000 COMMON Syntax: COMMON var[,var...] Does: variables/arrays passed by CHAIN without ALL Example: COMMON SCORE%,PLAYER$ CONT Syntax: CONT Does: continue after STOP or an untrapped break Example: CONT DELETE Syntax: DELETE range Does: remove stored program lines Example: DELETE 1000-1990 EDIT Syntax: EDIT line | EDIT ERL Does: edit a stored line or the last error line Example: EDIT ERL FIND Syntax: FIND string$[,range][,WORD] | FIND NEXT | FIND PREV Does: case-insensitive source search; WORD requires complete BASIC-name boundaries; NEXT/PREV repeat the last search and wrap at either end Example: FIND "PLAYERX",1000-5000,WORD Example: FIND NEXT REPLACE Syntax: REPLACE old$,new$[,range][,WORD] Does: direct-mode source replacement; WORD safely renames BASIC identifiers while ignoring strings, comments and DATA Example: REPLACE "PLAYERX","SHIPX",WORD XREF Syntax: XREF name | XREF array() | XREF line Does: syntax-aware cross-reference for names, arrays or literal line targets Example: XREF SCORE AUDIT Syntax: AUDIT Does: static checks for undefined literal targets, loop-structure mismatches and FN calls lacking DEF FN definitions. Also warns about built-in function names used for scalars or arrays. Scalars remain legal; conflicting arrays, including suffixed spellings, are rejected. May run inside a program and under CAPTURE. Example: AUDIT END Syntax: END Does: end program and close files Example: END HELP Syntax: HELP [name] Does: categorized built-in language reference; uses the full physical text screen and wraps at word boundaries, ignoring TXTWINDOW/VIEW PRINT while HELP is displayed Example: HELP LOADBMP LIST Syntax: LIST [range|ERL] [NOWAIT] Does: ERL lists the last error line; ranges: n, n-m, -m, n-; paging is standard, NOWAIT disables it; ESC aborts Example: LIST 1000-2000 NOWAIT LOAD Syntax: LOAD file$ Does: load ASCII BASIC program; omitted extension defaults to .BAS; closing quote may be omitted Example: LOAD "PIXELPROSE CREATEEXE Syntax: CREATEEXE file$ [NOGM] Does: create standalone Windows EXE from the current program; .EXE is added if omitted. By default copies the interpreter's embedded GM bank, otherwise THOREAU_GM.TBGM from the current directory if present. NOGM omits either bank source; an external bank may still be used at runtime. Direct mode only; requires a loaded BASIC program. Platform: Windows only Example: CREATEEXE "PixelProse" Example: CREATEEXE "GAME" NOGM CREATEEFI Syntax: CREATEEFI file$ [NOGM] Does: create standalone UEFI application from the current program; .EFI is added if omitted. Bank inclusion and NOGM behave as for CREATEEXE. NOGM removes an embedded bank as well as skipping the external file. Direct mode only; requires a loaded BASIC program. Platform: UEFI only Example: CREATEEFI "PixelProse" Example: CREATEEFI "GAME" NOGM MERGE Syntax: MERGE file$ Does: merge ASCII program lines Example: MERGE "EXTRA.BAS" NEW Syntax: NEW Does: clear program and variables Example: NEW RENUM Syntax: RENUM [new][,old][,increment] Does: renumber stored lines and complete literal references. Computed GOTO/GOSUB expressions are left untouched. TRON ranges and CHAIN ... DELETE ranges follow the renumbering; CHAIN start lines do not. Example: RENUM 1000,10,10 RUN Syntax: RUN [line|file$] Does: clear variables and run the stored program; a line number starts at that exact line; file$ is loaded first and defaults to .BAS when no extension is supplied; the closing filename quote may be omitted. Inside a program, RUN restarts through the execution controller without recursively growing the host stack. CLS:RUN is valid in direct mode. Repeated self-restarts remain interruptible with ESC. Example: RUN 1000 Example: RUN "GAME SAVE Syntax: SAVE file$[,A] Does: save ASCII BASIC program; omitted extension defaults to .BAS Example: SAVE "GAME",A STOP Syntax: STOP Does: print "Break in line", pause the program and preserve a continuation; CONT may resume after the STOP Example: STOP REM Syntax: REM comment or apostrophe comment Example: REM this is a comment FLOW / ERRORS / DIAGNOSTICS --------------------------- ERROR Syntax: ERROR n Does: raise an error Example: ERROR 5 FOR Syntax: FOR v=start TO limit [STEP step] ... NEXT | FOR END Does: FOR END exits the innermost active FOR and continues after its NEXT Example: FOR I=1 TO 10 STEP 2 PARFOR Syntax: PARFOR v=start TO limit [STEP positive-integer] ... NEXT [v] Does: execute independent iterations in parallel using the native JIT. Unlike FOR, execution order is not defined. The complete reachable loop/GOSUB graph is checked before workers start; unsafe or interpreter-only statements are rejected with a reason and suggested workaround rather than being executed concurrently by accident. Numeric and @ scalar scratch variables are private to each worker. Their worker-local final values are not a communication mechanism between iterations. Numeric/@ arrays are shared. Array reads are allowed; stores are accepted only when the compiler can prove that workers address disjoint elements/slices, normally because one subscript is exactly the PARFOR variable. Absolute PSET and supported LINE forms require an explicit colour and should target disjoint pixels/regions. Shared text cursor/output, WINDOW/VIEW transforms, active event handlers, TRON/TRACE watches, debugger breakpoints, nested PARFOR and any path requiring classic interpreter fallback are rejected. JIT must be ON. Sampled PROFILE modes are supported inside PARFOR; PROFILE EXACT/INTERPRETER is not. Start and limit must currently be integers; STEP must be a positive integer. With OPTION PARTHREADS 0, Thoreau autotunes worker count and may run a small PARFOR on one worker when threading would be slower. Windows and UEFI keep worker pools alive across repeated PARFOR calls during a RUN; on UEFI the AP pool is started through MP Services only as needed and is shut down when execution returns to Ready. Example: PARFOR Y=0 TO GRAMAXY FOR X=0 TO GRAMAXX PSET (X,Y),0,0,0 NEXT X NEXT Y PARTHREADS Syntax: PARTHREADS Does: read the configured PARFOR worker limit; 0 means automatic tuning Example: PRINT PARTHREADS PARWORKERS Syntax: PARWORKERS Does: effective number of workers used by the most recent PARFOR Example: PRINT PARWORKERS GOSUB Syntax: GOSUB expression Does: call a subroutine; computed targets are a Thoreau extension Example: GOSUB 9000 GOTO Syntax: GOTO expression Does: branch; computed targets are a Thoreau extension Example: GOTO BASE+OFFSET IF Syntax: IF condition THEN statement|literal-line [ELSE statement|literal-line] IF condition GOTO literal-line Does: conditional statement. THEN is required except for the GW-compatible IF condition GOTO line form. Elided THEN/ELSE branch targets are literal line numbers, not expressions. In nested single-line forms each ELSE binds to the nearest unmatched IF, including across GOSUB/RETURN. Example: IF SCORE>100 THEN 5000 ELSE 2000 NEXT Syntax: NEXT [v[,v...]] Does: end one or more nested FOR loops in the listed order Example: NEXT K,J,I ON Syntax: ON expr GOTO/GOSUB literal-line[,literal-line...] ON ERROR/BREAK GOTO line ON MOUSEMOVE/MOUSECLICK/MOUSEDOUBLECLICK GOSUB line Does: computed ON target-list entries are not accepted. The selector must be 0..255; 0 or a value beyond the supplied list falls through. ON ERROR GOTO traps errors silently by default and sets ERR/ERL. Example: ON CHOICE GOTO 1000,2000,3000 Example: ON ERROR GOTO 9000 Example: ON MOUSECLICK GOSUB 8000 RESUME Syntax: RESUME [NEXT|0|line] Does: leave an active error/break handler. RESUME line abandons control stacks left by the faulting path before transferring to the line. Example: RESUME NEXT RETURN Syntax: RETURN Does: return from GOSUB Example: RETURN TROFF Syntax: TROFF Does: disable line-number tracing Example: TROFF TRON Syntax: TRON [line[-line]] Does: trace all lines or only the selected line/range Example: TRON 1000-2000 TRACE Syntax: TRACE var[,var...] Does: watch selected scalar variables and print only when a value changes; each message is prefixed with the BASIC line which caused the change. TRACE OFF clears watches. With JIT ON, multi-statement/cross-line fast paths step aside while watches are active so changes are not lost. Example: TRACE SCORE%,ROOM% [420] {SCORE%=125} JIT Syntax: JIT ON | JIT OFF | JIT Does: enable/disable all bytecode and native JIT acceleration; JIT OFF forces the classic interpreter, while bare JIT reports ON/OFF Example: JIT OFF PROFILE Syntax: PROFILE [ALL] | PROFILE ON [MARK] | PROFILE MARK [ON|OFF] | PROFILE JIT | PROFILE SAMPLE | PROFILE EXACT | PROFILE INTERPRETER | PROFILE OFF | PROFILE CLEAR Does: measure executed source lines. ON/JIT/SAMPLE keep compiled execution active and use low-overhead timing samples; EXACT/INTERPRETER use exact interpreter profiling and disable compiled fast paths. Reports include RUNS, JITRUNS, INTRUNS and MODE. Bare PROFILE shows the 20 hottest lines; ALL shows all sampled lines in source order. Sampled profiling also works inside PARFOR. Parallel worker rows are labelled PAR and report sampled TIME/SHARE; their execution-count columns stay zero deliberately to avoid serializing workers on shared counters. PROFILE EXACT/INTERPRETER disables JIT and therefore cannot run PARFOR. PROFILE MARK, PROFILE MARK ON and PROFILE ON MARK enable statement execution marking, clear previous statistics/marks and start the normal JIT-aware sampled profiler. After RUN, LIST colours each executed statement according to the engine that actually handled it: GREEN executed by JIT YELLOW executed by the interpreter, but the statement itself has JIT support; surrounding control flow/region shape kept it interpreted in that run RED executed by the interpreter and currently has no JIT implementation for that statement/syntax NORMAL statement was not reached in the marked run PROFILE MARK OFF disables statement marking and restores ordinary LIST colours without discarding the collected timing/count statistics. PROFILE OFF stops profiling while retaining samples and the MARK colours from the last run. PROFILE CLEAR clears both statistics and statement marks. Source edits also invalidate the stored marks. Example: PROFILE ON MARK Example: PROFILE MARK OFF WHILE Syntax: WHILE condition ... WEND | WHILE END Does: WHILE END exits the innermost active WHILE and continues after WEND Example: WHILE A<10 WEND Syntax: WEND Does: end WHILE loop Example: WEND ERL Syntax: ERL Does: line number of last error Example: PRINT ERL ERR Syntax: ERR Does: last error number Example: PRINT ERR ERROR$ Syntax: ERROR$ Does: read-only text of the most recent error, including trapped errors. Empty at the start of a fresh RUN; persists across RESUME until the next error or RUN. ERROR n uses "User-defined error" with ERR=n. Cannot be assigned, READ, FIELD-mapped or used as a capture target. Example: PRINT "Error";ERR;" at line";ERL;": ";ERROR$ VARINFO Syntax: VARINFO [SIMPLE|FULL|0|1] Does: list scalar variables; FULL adds type/value/address; output pauses each screen Example: VARINFO FULL ARRAYINFO Syntax: ARRAYINFO [SIMPLE|FULL|0|1] Does: list arrays; FULL adds type/size/address; output pauses each screen Example: ARRAYINFO FULL VARIABLES / DATA / CONVERSION ----------------------------- CLEAR Syntax: CLEAR Does: clear variables/data Example: CLEAR DATA Syntax: DATA values Does: embedded program data. DATA occupies one BASIC statement, so : ends it and another statement may follow. Bare DATA and a trailing comma each contribute an empty value; consecutive commas do likewise. Example: DATA 10,20,"forest":PRINT "loaded" DEFDBL Syntax: DEFDBL letters Does: default double type; an unsuffixed name aliases its matching suffix Example: DEFDBL A-Z DEFI64 Syntax: DEFI64 letters Does: default 64-bit integer type; an unsuffixed name aliases its matching suffix Example: DEFI64 A-Z DEFINT Syntax: DEFINT letters Does: default integer type; an unsuffixed name aliases its matching suffix Example: DEFINT I-N DEFLNG Syntax: DEFLNG letters Does: default long type; an unsuffixed name aliases its matching suffix Example: DEFLNG L DEFSNG Syntax: DEFSNG letters Does: default single type; an unsuffixed name aliases its matching suffix Example: DEFSNG S DEFSTR Syntax: DEFSTR letters Does: default string type; an unsuffixed name aliases its matching suffix Example: DEFSTR A-C DIM Syntax: DIM array(bounds) Does: dimension a new array Example: DIM MAP%(100) LBOUND Syntax: LBOUND(array[,dimension]) Does: lower bound of an existing array dimension; currently 0 or 1 from OPTION BASE Example: PRINT LBOUND(A,2) UBOUND Syntax: UBOUND(array[,dimension]) Does: upper bound of an existing array dimension; dimension defaults to 1 Example: PRINT UBOUND(A) REDIM Syntax: REDIM array(bounds) Does: create or replace an array; contents are discarded and its address may change Example: REDIM MAP%(500) ERASE Syntax: ERASE array[,array...] Does: undefine arrays and return their storage for reuse; nonexistent arrays are ignored; other live array addresses do not move Example: ERASE MAP% OPTION Syntax: OPTION BASE 0|1 OPTION PARTHREADS 0..32 OPTION ERRORPRINT 0|1 Does: BASE selects the default array lower bound. PARTHREADS sets the PARFOR worker limit; 0 enables automatic tuning, while 1..32 caps the requested number of workers. ERRORPRINT controls printing of errors successfully caught by ON ERROR GOTO; default 0 is silent and matches GW-BASIC. Unhandled errors always print. Example: OPTION BASE 1 Example: OPTION PARTHREADS 0 Example: OPTION ERRORPRINT 1 READ Syntax: READ variables Does: consume DATA Example: READ X,Y,NAME$ RESTORE Syntax: RESTORE [line] Does: reset the DATA pointer. An explicit line must exist; READ then resumes at the first DATA statement at or after that line. Example: RESTORE 1000 SWAP Syntax: SWAP a,b Example: SWAP A,B CDBL Syntax: CDBL(x) Does: convert to double Example: X#=CDBL(A) CINT Syntax: CINT(x) Does: convert to integer Example: I%=CINT(X) CSNG Syntax: CSNG(x) Does: convert to single Example: S!=CSNG(X) CVD Syntax: CVD(s$) Does: MBF double from 8 bytes Example: X#=CVD(B$) CVI Syntax: CVI(s$) Does: integer from 2 bytes Example: I%=CVI(B$) CVS Syntax: CVS(s$) Does: MBF single from 4 bytes Example: S!=CVS(B$) MKD$ Syntax: MKD$(x) Does: 8-byte MBF double Example: B$=MKD$(X#) MKI$ Syntax: MKI$(n) Does: 2-byte integer Example: B$=MKI$(I%) MKS$ Syntax: MKS$(x) Does: 4-byte MBF single Example: B$=MKS$(S!) VARPTR Syntax: VARPTR(variable) Does: 64-bit address Example: PRINT HEX$(VARPTR(A)) HYPERCOMPLEX VARIABLES Syntax: name@ | name@(subscripts) | name@.R/.I/.J/.K/.E1..E7 Does: store complex, quaternion or octonion values in one native type; supports + - * /, =, <> and ^ with a real scalar exponent. Equality promotes component ranks as needed; ordering comparisons are invalid. Example: Q@=QUAT(1,2,3,4):PRINT Q@<>CPLX(1,2) FUNCTIONS --------- CRC32 Syntax: CRC32(string$) Does: IEEE CRC32 of the exact string bytes; result is 0..4294967295. The empty string returns 0. This detects accidental corruption; it is not authentication or a cryptographic hash. Example: PRINT CRC32("abc") Prints 891568578. TEXTSTATS Syntax: TEXTSTATS text$(),first,last,words,characters Does: count an inclusive range in a one-dimensional string array. first and last are actual array indices, respecting OPTION BASE; the two outputs are numeric scalars. Invalid array/range arguments error. Characters sum BASIC string byte lengths, excluding line separators. Word bytes are letters, digits, underscore and bytes >=128; internal apostrophes/hyphens between word bytes keep a word together. Array entries separate words. This is a byte-based count, not Unicode linguistic segmentation. Use sufficiently wide numeric outputs. Example: DEFI64 A-Z:OPTION BASE 0:DIM T$(1) T$(0)="Don't re-enter":T$(1)="a poem" TEXTSTATS T$(),0,1,W,C:PRINT W,C Returns 4 words and 20 characters. DEF FN Syntax: DEF FNname(args)=expr | DEF FN name(args)=expr Does: define a one-expression user function. Whitespace after FN is accepted contextually. Function-name suffix/default type and parameter suffix/DEFxxx types are enforced in both interpreter and JIT. Recursive calls are depth-guarded so runaway recursion raises Out of memory rather than overflowing the host stack. Example: DEF FN SQUARE%(X)=X*X IIF Syntax: IIF(condition,ifTrue,ifFalse) Does: evaluate condition, then evaluate and return only the selected branch; the unselected expression is not evaluated Example: DEF FNSAFE(X)=IIF(X=0,0,1/X) ABS Syntax: ABS(x) Does: absolute value; for @ values returns Euclidean magnitude Example: PRINT ABS(CPLX(3,4)) CPLX Syntax: CPLX(real,i) Does: construct a complex @ value Example: Z@=CPLX(3,4) QUAT Syntax: QUAT(real,i,j,k) Does: construct a quaternion @ value Example: Q@=QUAT(1,2,3,4) OCT Syntax: OCT(real,e1,e2,e3,e4,e5,e6,e7) Does: construct an octonion @ value Example: O@=OCT(1,2,3,4,5,6,7,8) CONJ Syntax: CONJ(x) Does: hypercomplex conjugate Example: PRINT CONJ(CPLX(3,4)) INV Syntax: INV(x) Does: multiplicative inverse; A@/B@ is defined as A@*INV(B@) Example: PRINT INV(QUAT(1,2,3,4)) NORM Syntax: NORM(x) Does: Euclidean magnitude Example: PRINT NORM(CPLX(3,4)) NORM2 Syntax: NORM2(x) Does: squared Euclidean norm Example: PRINT NORM2(CPLX(3,4)) COMP Syntax: COMP(x,n) Does: return hypercomplex component 0..7; component 0 is real Example: PRINT COMP(QUAT(1,2,3,4),3) ASC Syntax: ASC(s$) Does: character code Example: PRINT ASC("A") ATN Syntax: ATN(x) Does: arctangent Example: PRINT ATN(1) CHR$ Syntax: CHR$(n) Does: one-character string Example: PRINT CHR$(65) COS Syntax: COS(x) Does: cosine; accepts scalar or @ values Example: PRINT COS(CPLX(1,2)) COSH Syntax: COSH(x) Does: hyperbolic cosine; accepts scalar or @ values Example: PRINT COSH(QUAT(1,2,3,4)) EXP Syntax: EXP(x) Does: exponential; accepts scalar or @ values Example: PRINT EXP(CPLX(0,1)) FIX Syntax: FIX(x) Does: truncate toward zero Example: PRINT FIX(-3.7) HEX$ Syntax: HEX$(n) Does: hexadecimal string Example: PRINT HEX$(255) INSTR Syntax: INSTR([start,]string$,search$) Example: PRINT INSTR("FOREST","REST") INT Syntax: INT(x) Does: floor Example: PRINT INT(-3.7) LCASE$ Syntax: LCASE$(s$) Does: convert ASCII A-Z to lowercase Example: PRINT LCASE$("GORSE") UCASE$ Syntax: UCASE$(s$) Does: convert ASCII a-z to uppercase Example: PRINT UCASE$("gorse") LEFT$ Syntax: LEFT$(s$,n) Example: PRINT LEFT$("THOREAU",3) LEN Syntax: LEN(s$) Example: PRINT LEN("BASIC") LOG Syntax: LOG(x) Does: natural logarithm; @ values use the documented principal branch Example: PRINT LOG(QUAT(-1,0,0,0)) MID$ Syntax: MID$(s$,start[,len]) or MID$(s$,start[,len])=value$ Example: MID$(A$,2,3)="XYZ" OCT$ Syntax: OCT$(n) Does: octal string Example: PRINT OCT$(64) RIGHT$ Syntax: RIGHT$(s$,n) Example: PRINT RIGHT$("THOREAU",4) RND Syntax: RND[(x)] Does: random number Example: PRINT RND(1) SGN Syntax: SGN(x) Does: sign Example: PRINT SGN(-9) SIN Syntax: SIN(x) Does: sine; accepts scalar or @ values Example: PRINT SIN(CPLX(1,2)) SINH Syntax: SINH(x) Does: hyperbolic sine; accepts scalar or @ values Example: PRINT SINH(QUAT(1,2,3,4)) SPACE$ Syntax: SPACE$(n) Example: PRINT "A"+SPACE$(5)+"B" SQR Syntax: SQR(x) Does: square root; @ values use the documented principal root Example: PRINT SQR(CPLX(-1,0)) SQRT Syntax: SQRT(x) Does: alias for SQR; @ values use the documented principal root Example: PRINT SQRT(OCT(-1,0,0,0,0,0,0,0)) STR$ Syntax: STR$(x) Does: number to string; @ values use canonical component notation Example: A$=STR$(42) STRING$ Syntax: STRING$(n,char) Example: PRINT STRING$(20,"*") TAN Syntax: TAN(x) Does: tangent; accepts scalar or @ values Example: PRINT TAN(CPLX(1,2)) TANH Syntax: TANH(x) Does: hyperbolic tangent; accepts scalar or @ values Example: PRINT TANH(QUAT(1,2,3,4)) VAL Syntax: VAL(s$) Does: string to number Example: PRINT VAL("123.5") VIDEOMODES Syntax: VIDEOMODES() Does: number of physical/display video modes available for enumeration Example: FOR I=0 TO VIDEOMODES()-1 INPUT / OUTPUT -------------- CLS Syntax: CLS [@n] Does: clear screen/text window; Ctrl+L at the interactive prompt clears the screen and current edit line Example: CLS COLOR Syntax: COLOR fg[,bg] | COLOR r,g,b | COLOR r,g,b,rb,gb,bb Does: set foreground/background; 0-15 = palette, >15 = packed 0xRRGGBB Example: COLOR 255,136,0,16,16,16 CSRLIN Syntax: CSRLIN Does: current text row Example: PRINT CSRLIN INKEY$ Syntax: INKEY$ Does: nonblocking key string; supported extended keys return the classic two-byte form CHR$(0)+CHR$(DOS scan) Example: K$=INKEY$ Example: IF K$=CHR$(0)+CHR$(72) THEN PRINT "UP" KEYDOWN Syntax: KEYDOWN(key$) Does: -1 while the named key is currently held; does not consume INKEY$ Example: IF KEYDOWN("LEFT") AND KEYDOWN("SPACE") THEN GOSUB 9000 KEYSTATEAVAILABLE Syntax: KEYSTATEAVAILABLE or KEYSTATEAVAILABLE() Does: -1 when true held-key state is available; UEFI requires raw USB HID Example: IF NOT KEYSTATEAVAILABLE THEN PRINT "No held-key state" KEYREPEAT Syntax: KEYREPEAT delayMilliseconds,rateHz | KEYREPEAT DEFAULT Does: custom typematic timing on Windows and raw USB HID UEFI; firmware UEFI fallback keeps firmware repeat timing Example: KEYREPEAT 0,30 MOUSE Syntax: MOUSE ON | MOUSE OFF Does: show or hide the pointer; mouse state remains readable either way Example: MOUSE ON MOUSEPOS Syntax: MOUSEPOS x,y Does: set logical mouse position in physical framebuffer pixels Example: MOUSEPOS 320,240 MOUSEX / MOUSEY Syntax: MOUSEX() | MOUSEY() Does: current logical pointer coordinates in framebuffer pixels Example: PRINT MOUSEX(),MOUSEY() MOUSEB Syntax: MOUSEB() Does: button bitmask: 1 left, 2 right, 4 middle where available Example: IF MOUSEB() AND 1 THEN PRINT "LEFT" MOUSEWHEEL Syntax: MOUSEWHEEL() Does: cumulative signed wheel movement Example: W=MOUSEWHEEL() MOUSEPRESENT Syntax: MOUSEPRESENT or MOUSEPRESENT() Does: -1 when a pointing device is available, else 0 Example: IF MOUSEPRESENT THEN MOUSE ON MOUSEINFO Syntax: MOUSEINFO Does: show detected pointer support and the active platform backend Example: MOUSEINFO BEEP Syntax: BEEP Does: emit the same BEL as PRINT CHR$(7); does not require the GM bank Example: BEEP CLIPBOARD Syntax: CLIPBOARD stringExpr Does: copy text to the clipboard. Windows converts CP437 BASIC bytes to Unicode desktop text; UEFI stores the BASIC bytes unchanged in the Thoreau-session clipboard. Example: CLIPBOARD "Caf"+CHR$(130) CLIPBOARD$ Syntax: CLIPBOARD$ Does: return current clipboard text. Windows converts Unicode to CP437; characters unavailable in CP437 become '?'. Example: A$=CLIPBOARD$ INPUT Syntax: INPUT [;][prompt;|prompt,] variable[,variable...] | INPUT #n,... Does: read values; INSERT toggles insert/overwrite mode and the steady cursor shape shows the active mode. A leading semicolon keeps the cursor on the current line after Enter instead of advancing to the next text row. Malformed interactive input prints ?Redo from start; numeric overflow is a real Overflow error and can be caught by ON ERROR GOTO. Example: INPUT ;"A=",A LINE INPUT Syntax: LINE INPUT [;][prompt;|prompt,] stringVar | LINE INPUT #n,stringVar Does: read a whole line. Console input uses the same insert/overwrite editor as INPUT; a leading semicolon keeps the cursor on the current text line after Enter. Either comma or semicolon may follow the prompt; neither separator adds a question mark. Example: LINE INPUT "Title";T$ INPUT$ Syntax: INPUT$(count[,[#]n]) Does: without #n, block until count raw keyboard characters are available and return them without echo; TAB/ESC and other ordinary control bytes pass through. Extended navigation/function keys contribute CHR$(0), while INKEY$ exposes the full CHR$(0)+scan pair. With #n, read count bytes from the file. Example: A$=INPUT$(1) LOCATE Syntax: LOCATE [@n,]row,col Does: move the text cursor using 1-based coordinates. With VIEW PRINT, row remains an absolute whole-screen row and must lie inside the viewport. Example: LOCATE 10,20 POS Syntax: POS(x) Does: current text column Example: PRINT POS(0) PRINT Syntax: PRINT expressions; PRINT USING; PRINT #; PRINT @; PRINT WRAP [width,]string$; PRINT JUSTIFY [width,]string$ Does: screen/text-window output recognizes CHR$(7) BEL, CHR$(9) 8-column TAB, CHR$(10)/CHR$(13) newline and CHR$(12) clear-view control bytes. PRINT# writes file data and does not reinterpret them as screen controls. Example: PRINT WRAP 60,TEXT$ SPC Syntax: SPC(n) Does: PRINT spacing Example: PRINT "A";SPC(5);"B" TAB Syntax: TAB(n) Does: PRINT tab position Example: PRINT TAB(20);"column 20" TXTWINDOW Syntax: TXTWINDOW col1,row1,col2,row2 sets the normal text region; bare TXTWINDOW restores full screen; TXTWINDOW @n,col1,row1,col2,row2 defines a named region Does: define a 1-based text-cell rectangle (columns and rows, not graphics x/y coordinates) Example: TXTWINDOW 1,20,80,30 TXTMAXX Syntax: TXTMAXX Does: text columns Example: PRINT TXTMAXX TXTMAXY Syntax: TXTMAXY Does: text rows Example: PRINT TXTMAXY WRITE Syntax: WRITE values or WRITE #n,values Example: WRITE "room",ROOM% NETWORK ------- TCP Syntax: TCP OPEN slot,host$,port | TCP SEND slot,data$ | TCP CLOSE slot | TCP TIMEOUT milliseconds Does: TCP/IPv4 client networking with slots 0..7; timeout range 1..600000 ms Example: TCP OPEN 0,"example.com",80 TCPRECV$ Syntax: TCPRECV$(slot[,maxBytes]) Does: receive up to maxBytes from a TCP slot; default 4096, maximum 1048576 Example: A$=TCPRECV$(0) TCPCONNECTED Syntax: TCPCONNECTED(slot) Does: -1 while the TCP slot is open and connected Example: IF TCPCONNECTED(0) THEN PRINT "CONNECTED" TCPEOF Syntax: TCPEOF(slot) Does: -1 after the remote peer closes the connection Example: IF TCPEOF(0) THEN TCP CLOSE 0 DNS$ Syntax: DNS$(host$) Does: resolve a host name to an IPv4 dotted-decimal string Example: PRINT DNS$("example.com") NETPRESENT Syntax: NETPRESENT() Does: -1 when a usable IPv4 network stack is available Example: IF NOT NETPRESENT() THEN PRINT "NO NETWORK" NETINFO Syntax: NETINFO Does: display network backend, protocol/fallback availability, IPv4 configuration and the most recent network error; UEFI includes SNP/PXE/Managed Network/DHCP4/IP4/UDP4/DNS4/TCP4/HTTP/TLS status Example: NETINFO HTTPGET$ Syntax: HTTPGET$(url$[,headers$]) Does: HTTP/HTTPS GET; optional headers are CR/LF-separated Name: value lines; response body is limited to 1 MiB Example: J$=HTTPGET$("https://example.com/") HTTPSTATUS Syntax: HTTPSTATUS() Does: numeric status from the most recent HTTPGET$ Example: PRINT HTTPSTATUS() NETERROR$ Syntax: NETERROR$() Does: text for the most recent network error Example: IF J$="" THEN PRINT NETERROR$() CAPTURE TEXT OUTPUT ------------------- CAPTURE Syntax: CAPTURE stringVar | CAPTURE [#]fileNumber | CAPTURE OFF Does: redirect ordinary PRINT, info commands, HELP and directory listings into a scalar string variable or an already open OUTPUT/APPEND file. PRINT # keeps its explicit destination. Graphics, input and sound are unaffected. Paging prompts and waits are bypassed during capture. Example: CAPTURE info$: SOUND INFO: NETINFO: CAPTURE OFF: PRINT info$; String capture starts empty and buffers up to 64 MiB, subject to string space. Read the result after CAPTURE OFF: the buffer is published when capture ends, another capture starts, or the program stops/exits. Assigning the destination while capture is active does not alter the pending buffer. File capture writes through BASIC's buffered file table; OFF flushes it and CLOSE ends capture. Starting a new capture finishes the previous one; OFF when inactive is harmless. CLEAR, NEW and a fresh RUN cancel capture along with variables. OPEN "diagnostics.txt" FOR APPEND AS #1 CAPTURE #1 SOUND INFO MIDINFO CAPTURE OFF CLOSE #1 Capture persists across direct commands; Ready prompts stay on screen and are excluded from the result. End capture before requesting interactive input. Strings use CHR$(13) line separators; files use CRLF, like PRINT #. BASIC's existing byte encoding is retained. There is no per-statement | capture suffix. SOUND / WAV / MIDI ------------------ Thoreau Sound uses a 48 kHz stereo render domain. The public musical instrument engine is the GM/GS wavetable in THOREAU_GM.TBGM. There is no BASIC command for selecting a synthetic replacement engine. SOUND Syntax: SOUND ON | SOUND OFF | SOUND RESET | SOUND INFO SOUND PRELOAD [workers] | SOUND GROUPS | SOUND LIST [group] SOUND MASTER value Does: control the PCM subsystem and GM bank. PRELOAD accepts 0 automatic, 1 serial, or 2..8 as a decoder cap. INFO reports backend, bank, loader, WAV-pool and DSP diagnostics without forcing a bank load. TBGM2 raw, TBGM3 lossless and TBGM4 Opus banks are accepted and fully expanded before playback. ON/OFF confirmations are direct-mode only. PRELOAD is quiet in programs unless captured. Use SOUND ON before NOTE/SOUNDKEY; PLAYMID and PLAYWAV start output automatically. Example: SOUND PRELOAD 4 INSTRUMENT Syntax: INSTRUMENT channel,id[,engine] Does: select GM program 0..127 or drum kit 128..131 on channel 0..31; resets channel controls for new notes. Optional engine accepts 2, "GM" or "WAVETABLE" for compatibility; all select the same engine. Example: INSTRUMENT 0,40 NOTE Syntax: NOTE channel,note[,velocity] Does: start a MIDI-style note; note and velocity are 0..127 Example: NOTE 0,60,100 NOTEOFF Syntax: NOTEOFF channel,note Does: release a NOTE voice Example: NOTEOFF 0,60 SOUNDCTL Syntax: SOUNDCTL channel,control,value Does: change a live sound control by number 0..24 or by name. Names include VOLUME, PAN, BRIGHTNESS, DAMPING, ATTACK, RELEASE, PRESSURE, TIMBRE, NOISE, VIBRATO, VIBRATE, BODY, HARDNESS, BREATH, REED, BOW, BAG, DETUNE, SPREAD, POSITION, RESONANCE, DRIVE, AIR, MUTE and DRONES. Model-only legacy controls which do not apply to a wavetable program are accepted but have no effect. Example: SOUNDCTL 0,"VOLUME",.8 SOUNDKEY Syntax: SOUNDKEY channel,key,pitch,pressure,x,y,gate Does: expressive wavetable note control. key is 0..65535, pitch is a fractional MIDI note 0..127, pressure is 0..1 and X/Y are -1..1. Repeated gate=1 updates a live note without retriggering; send gate=0 before starting a new strike with the same key. Example: SOUNDKEY 0,1,69.25,.85,.1,-.2,1 SOUNDPRESENT Syntax: SOUNDPRESENT() Does: -1 when a PCM output backend is available Example: IF SOUNDPRESENT() THEN SOUND ON SOUNDACTIVE Syntax: SOUNDACTIVE() Does: number of currently active note voices Example: PRINT SOUNDACTIVE() SOUNDLOAD Syntax: SOUNDLOAD() Does: recent audio-render CPU load as a percentage of the 128-frame deadline Example: PRINT SOUNDLOAD() SOUNDNAME$ Syntax: SOUNDNAME$(id[,engine]) Does: GM catalog name for instrument/kit 0..131 without loading the bank. Optional engine accepts 2, "GM" or "WAVETABLE", as for INSTRUMENT Example: PRINT SOUNDNAME$(109) SOUNDAVAILABLE Syntax: SOUNDAVAILABLE(id) Does: -1 when the loaded GM bank contains the instrument/kit; loads the bank when necessary Example: PRINT SOUNDAVAILABLE(40) SOUNDGROUP Syntax: SOUNDGROUP(id[,engine]) Does: numeric catalog group for instrument/kit 0..131 without loading the bank. Groups 0..15 each contain eight consecutive GM programs; group 16 contains kits 128..131. Bank contents do not change these assignments; use SOUNDAVAILABLE to check sample availability. Optional engine accepts 2, "GM" or "WAVETABLE". Example: PRINT SOUNDNAME$(109);" / ";SOUNDGROUP$(SOUNDGROUP(109)) SOUNDGROUP$ Syntax: SOUNDGROUP$(group) Does: name of GM group 0..15 or drum-kit group 16 Example: PRINT SOUNDGROUP$(5) LOADWAV Syntax: LOADWAV slot,filename$ Does: preload mono/stereo WAV, native FLAC or Ogg Opus into slot 0..255. Detects contents independently of extension. Completely decodes and resamples to resident 48 kHz float32 PCM before returning; a failed or cancelled load preserves the previous slot. The decoded slot pool limit is 2 GiB. No external codec DLL or converter is needed. WAV PCM/float support is unchanged. Native FLAC accepts 4..32-bit, 4..192 kHz audio; float32 storage rounds precision above 24 bits. Ogg Opus decodes to 16-bit PCM before conversion to float32 and honors pre-skip, end trimming and header gain. Sequential chained links require matching channel counts. Ogg FLAC, multiplexed Ogg and multichannel/surround files are rejected. Corrupt/incomplete streams fail the load. WAVINFO identifies source and decoded formats. Example: LOADWAV 0,"SOUND.FLAC" Example: LOADWAV 1,"SOUND.OPUS" PLAYWAV Syntax: PLAYWAV slot[,channel[,loop[,volume[,pan]]]] Does: play asynchronously. WAV channels are 0..63; omitted or -1 selects a free channel. loop is 0/1, volume 0..1, pan -1..1. Starts sound output automatically. Uses the PCM already loaded by LOADWAV, with no file reads or decompression during playback. Example: PLAYWAV 0,-1,0,.8,0 STOPWAV Syntax: STOPWAV [channel] Does: stop one WAV channel or all with a short fade; MIDI/note voices and loaded WAV slots are unaffected Example: STOPWAV WAITWAV Syntax: WAITWAV [channel] Does: wait for one/all WAV channels, including paused/looping playback; ESC cancels the wait/playback. Normal END leaves asynchronous WAV playback running. Example: WAITWAV 3 PAUSEWAV Syntax: PAUSEWAV [channel] Does: pause one/all WAV channels at their rendered position Example: PAUSEWAV 0 RESUMEWAV Syntax: RESUMEWAV [channel] Does: resume paused WAV channels with a short ramp Example: RESUMEWAV 0 WAVCTL Syntax: WAVCTL channel,volume[,pan] Does: live volume 0..1 and optional pan -1..1, smoothed over a short ramp Example: WAVCTL 0,.5,-.4 DELWAV Syntax: DELWAV slot Does: stop all instances of the slot immediately and free its decoded PCM Example: DELWAV 0 WAVINFO Syntax: WAVINFO [slot] Does: show WAV pool/memory use or one source/decoded format Example: WAVINFO 0 WAVCHANNEL Syntax: WAVCHANNEL() Does: channel chosen by the most recent successful PLAYWAV, or -1 after reset Example: PRINT WAVCHANNEL() WAVACTIVE Syntax: WAVACTIVE() Does: number of occupied WAV channels, including paused/fading channels Example: PRINT WAVACTIVE() WAVPLAYING Syntax: WAVPLAYING([channel]) Does: -1 when one/specified WAV channel is playing or fading; paused is not counted as playing Example: PRINT WAVPLAYING() WAVSTATE Syntax: WAVSTATE(channel) Does: 0 idle, 1 playing, 2 paused, 3 stopping Example: PRINT WAVSTATE(0) WAVPOS Syntax: WAVPOS(channel) Does: rendered position in seconds; wraps for looping playback Example: PRINT WAVPOS(0) WAVLENGTH Syntax: WAVLENGTH(slot) Does: decoded duration in seconds; an unloaded slot is an error Example: PRINT WAVLENGTH(0) WAVLOADED Syntax: WAVLOADED(slot) Does: -1 if the WAV slot is loaded, else 0 Example: PRINT WAVLOADED(0) WAVSLOT Syntax: WAVSLOT(channel) Does: loaded slot assigned to an occupied WAV channel, or -1 if idle Example: PRINT WAVSLOT(0) LOADMID Syntax: LOADMID slot,filename$ Does: load Standard MIDI File type 0/1 or RIFF RMID into slot 0..255; failed loads preserve the previous slot Example: LOADMID 0,"SONG.MID" PLAYMID Syntax: PLAYMID slot[,loop] Does: asynchronous playback through Thoreau's GM wavetable; loop is 0/1. MIDI parts use channels 0..15. Example: PLAYMID 0,1 STOPMID Syntax: STOPMID Does: stop MIDI voices while keeping loaded scores and unrelated sound Example: STOPMID WAITMID Syntax: WAITMID Does: wait for score events and release tails while servicing audio and ESC; normal END leaves asynchronous MIDI playback running Example: WAITMID DELMID Syntax: DELMID slot Does: stop that slot if it is playing and free its MIDI events Example: DELMID 0 MIDINFO Syntax: MIDINFO slot Does: show duration, event count and wavetable instrument/drum coverage; may load the GM bank Example: MIDINFO 0 MIDCC Syntax: MIDCC part,controller,value Does: send one supported MIDI controller to part 0..15, or use part -1 for all parts. Later score events may replace the value. Example: MIDCC -1,91,100 MIDCCINFO Syntax: MIDCCINFO Does: show live MIDI parts/voices, CC91/93/94, manual MIDFX override, return levels and effect send/wet peak meters Example: MIDCCINFO MIDFX Syntax: MIDFX reverb,chorus,delay | MIDFX AUTO | MIDFX OFF | MIDFX CLEAR Does: force all-part reverb/chorus/delay sends from 0..127 for audition. AUTO follows the score; OFF forces dry sends; CLEAR discards existing wet tails without changing the current override. Example: MIDFX 127,0,0 MIDPLAYING Syntax: MIDPLAYING() Does: -1 while MIDI score events or release tails are rendering Example: PRINT MIDPLAYING() MIDSTATE Syntax: MIDSTATE() Does: 0 stopped, 1 score, 2 release tails Example: PRINT MIDSTATE() MIDPOS Syntax: MIDPOS() Does: rendered score position in seconds, capped at score length Example: PRINT MIDPOS() MIDLENGTH Syntax: MIDLENGTH(slot) Does: score duration in seconds, excluding release tails Example: PRINT MIDLENGTH(0) FILES / DIRECTORIES ------------------- Current path and filename rules Path strings support up to 4,095 bytes, including any automatic extension. This is a full-path limit, not a promise of 4,095-character leaf names: filesystems commonly impose a smaller component limit. Windows resolved absolute paths must also fit. Long paths should be assembled in strings. Generated suffixes such as .previous and .version-... require extra headroom. Embedded NULs, overlong paths and unrepresentable names are rejected. Original case is preserved through OPEN, LOAD/SAVE/MERGE/CHAIN/RUN, DIR/FILES/GETFILES, NAME/KILL, directory, binary, graphics and audio file commands, CREATEEXE/CREATEEFI and the monitor's LOAD/SAVE. BASIC keywords remain case-insensitive. File masks use case-sensitive * and ? matching; *.* also includes names without an extension. Native filesystem name lookup retains its own rules; Windows lookup is not universally case-sensitive. Windows uses TB's existing CP437 filename conversion and long drive/UNC path support; UEFI retains its existing one-byte filename interface. The path extension does not introduce arbitrary Unicode filenames. GETFILES Syntax: GETFILES names$(),count[,filespec$[,flags]] Does: create/replace a one-dimensional string array; no DIM is needed. count is a numeric scalar. Default filespec is * in the current directory; a specification may include a directory path. No recursion. Default flags are 7: add 1 for files matching the mask, 2 for all child directories regardless of mask, 4 for .. when a parent exists. Thus 1 gives files only, 6 directories/parent, and 0 an empty list. .. comes first, then directories, then files. Groups are alphabetical with an exact-byte tie-break for case variants. Names preserve case; child directories end in backslash. Entries are relative to the listed folder; GETFILES does not change the working directory. OPTION BASE applies. Empty results set count=0 and leave one empty array element; always iterate by count. Listing errors/interruption preserve the previous array and count. Replacing the array invalidates previously retained element addresses. There is no GETDIRS command. Example: GETFILES ENTRIES$(),N,"CHAPTERS\*.txt",7 Example: GETFILES FILES$(),N,"*.BAS",1 FLUSH Syntax: FLUSH [#n[,#m...]] Does: drain BASIC output buffers and request FlushFileBuffers on Windows or file Flush on UEFI. With no numbers, flush all open writable files. An explicitly selected read-only file raises Bad file mode. Handles stay open. Failures can be trapped with ON ERROR. Example: PRINT #1,"checkpoint":FLUSH #1 FILECRC Syntax: FILECRC(path$) Does: return IEEE CRC32 of the exact file bytes, in 0..4294967295; return -1 if the file cannot be opened/is unavailable. Invalid paths and failed reads can raise errors. Equal CRCs are not proof against intentional modification; use byte comparison where required. Example: PRINT FILECRC("Manuscript.txt") FILECOMMIT Syntax: FILECOMMIT staged$,target$ Does: flush a staged file, rotate an existing target to target.previous, promote the staged file and flush the promoted target. The previous copy is retained; reserve the .previous name. Failures raise errors. Filesystem rename, especially FAT, is not a power-atomic transaction; maintain an independent recovery generation for critical data. Example: FILECOMMIT "Manuscript.txt.new","Manuscript.txt" FILECOPY Syntax: FILECOPY source$,target$,result Does: stage the copy in target.new, flush it and verify it byte-for-byte against the source, then promote it using FILECOMMIT. Reserve both target.new and target.previous. result is -1 on success, 0 when unavailable or copying fails, including copy-buffer allocation failure. Invalid arguments can raise errors. Destination directories are not created. Check the result and handle errors; a flush request depends on the device. Example: FILECOPY "Manuscript.txt","E:\Backup\Manuscript.txt",OK IF OK=0 THEN PRINT "BACKUP UNAVAILABLE" SESSIONLOCK Syntax: SESSIONLOCK path$,result Does: hold an exclusive Windows file handle for a recovery-folder lock; result=-1 if held, 0 if unavailable. UEFI is a single foreground application and uses its existing file interface. Repeating the held path succeeds; a different path while locked raises an error. Bare CLOSE or END releases the lock; ABORTFILES retains it. Example: SESSIONLOCK ".my-lock",OK IF OK=0 THEN PRINT "ANOTHER WRITER OR UNAVAILABLE STORAGE":END ABORTFILES Syntax: ABORTFILES Does: discard BASIC output buffers and close file handles after a failed transaction without retrying pending writes. File CAPTURE routing is cancelled. An active SESSIONLOCK remains held. This deliberately discards unsent data; use ordinary CLOSE on the successful path. Example: ABORTFILES STATEWRITE / STATELOAD Syntax: STATEWRITE base$,schema$,result STATELOAD base$,schema$,result Does: save/restore selected ordinary numeric/string scalars and one-dimensional arrays. schema$ is a space-separated list of scalar names and array names ending in (). Names/types, order, OPTION BASE and exact array bounds must match on load; predeclare the arrays. Type suffixes and DEFxxx defaults matter. @ values are unsupported. STATEWRITE alternates base.a and base.b generations, retaining the preceding valid slot while writing the next. A generation contains its number, lengths, header/payload CRC32 and a commit trailer. TB requests a platform flush, closes and readback-verifies completion. result=-1 on success. Unchanged state is flushed again and returns -1 without a new generation. Failures can raise BASIC errors. STATELOAD selects the newest complete valid generation, validates schema and payload and stages allocations before publishing restored values together. result=-1 if restored, 0 if both files are absent. Present files with no valid generation raise No valid recovery generation; mismatched schemas and other failures also raise errors. A failed restore does not publish partially restored state. The total payload ceiling is 256 MiB. This saves only the explicit schema, not the program or whole VM. Leave space for .a/.b suffixes. CRC32 detects accidental damage, not authenticity; physical device durability depends on the platform honoring its flush requests. Example: 10 DEFI64 A-Z:OPTION BASE 0 20 DIM L$(1):L$(0)="First line":L$(1)="Second line":CUR=1 30 STATEWRITE "example-state","L$() CUR",OK 40 IF OK<>-1 THEN END 50 L$(0)="changed":CUR=0 60 STATELOAD "example-state","L$() CUR",OK 70 IF OK THEN PRINT L$(0);CUR APPEND Syntax: APPEND Does: OPEN mode Example: OPEN "LOG.TXT" FOR APPEND AS #1 AS Syntax: AS Does: OPEN/FIELD syntax word Example: OPEN "SAVE.DAT" FOR OUTPUT AS #1 BLOAD Syntax: BLOAD file$[,address] Does: load GW memory image Example: BLOAD "IMAGE.BIN",&H10000 BSAVE Syntax: BSAVE file$,address,length Does: save GW memory image Example: BSAVE "IMAGE.BIN",&H10000,4096 CHDIR Syntax: CHDIR path$ Does: change directory Example: CHDIR "GAMES" CLOSE Syntax: CLOSE [#n,...] Does: close files Example: CLOSE #1 EOF Syntax: EOF(n) Does: end-of-file state Example: WHILE NOT EOF(1) FIELD Syntax: FIELD #n,width AS s$,... Does: map random-file record fields Example: FIELD #1,20 AS NAME$,4 AS SCORE$ DIR Syntax: DIR [pattern$][,S][,W][,P] Does: alias for FILES; names/paths retain their exact case and spelling. File masks are case-sensitive. S recurses, W uses wide listing, P pauses; ESC aborts listing/traversal. Example: DIR "*.BAS",S,W,P FILES Syntax: FILES [pattern$][,S][,W][,P] Does: names/paths retain exact case and spelling. Directories come first with [DIR]; groups sort alphabetically with an exact-byte tie-break for case variants. * and ? masks match case-sensitively; *.* also includes extensionless files. S recurses, W uses wide output, P pauses; ESC aborts. Example: FILES "*.BMP",W GET Syntax: GET (x1,y1)-(x2,y2),array or GET #n[,record] Does: graphics GET stores a full 24-bit framebuffer rectangle in a numeric array Example: GET (0,0)-(63,63),SPR& File example: GET #1,5 KILL Syntax: KILL filespec$ Does: delete files matching case-sensitive * and ? masks; *.* also matches extensionless files. Wildcard deletion is non-recursive and never removes directories. Names retain their original case. Example: KILL "*.TMP" LOC Syntax: LOC(n) Does: file position/record Example: PRINT LOC(1) LOF Syntax: LOF(n) Does: file length Example: PRINT LOF(1) LSET Syntax: LSET field$=value$ Does: left-align random field Example: LSET NAME$="THOREAU" MKDIR Syntax: MKDIR path$ Does: create directory Example: MKDIR "SAVES" NAME Syntax: NAME old$ AS new$ Does: rename file/directory Example: NAME "OLD.SAV" AS "NEW.SAV" OPEN Syntax: OPEN file$ FOR mode AS #n or classic OPEN mode,#n,file$ Example: OPEN "SAVE.DAT" FOR INPUT AS #1 OUTPUT Syntax: OUTPUT Does: OPEN mode Example: OPEN "OUT.TXT" FOR OUTPUT AS #1 PUT Syntax: PUT (x,y),array[,PSET|PRESET|XOR|AND|OR] or PUT #n[,record] Does: graphics PUT restores 24-bit GET data; default graphics mode is XOR Example: PUT (200,100),SPR&,PSET File example: PUT #1,5 RMDIR Syntax: RMDIR path$ Does: remove empty directory Example: RMDIR "EMPTYDIR" RSET Syntax: RSET field$=value$ Does: right-align random field Example: RSET SCORE$=MKI$(1000) GRAPHICS -------- SELECTBOX Syntax: SELECTBOX x,y,width,height,maxEntry,columns,items$(),count,choice [,fg,bg[,selectedFg,selectedBg]][,frame] Does: draw a modal selector in physical text cells, with x/y starting at 1. width/height include the frame, must be at least 3 by 3, and must fit the physical text screen. Coordinates are independent of TXTWINDOW and VIEW PRINT. columns fill across each row and divide the interior with a separating space. maxEntry limits display width; labels are also clipped to the column width. Array strings are intact. items$() is a one-dimensional string array; count starts at its OPTION BASE. choice is a numeric scalar containing the initial and returned actual array index. An invalid initial index selects the first item. Escape and an empty list return -1. Check before indexing. Colors use COLOR conventions: supply a normal pair or both normal and selected pairs. Defaults are current colors with reversed selection. A final frame argument can stand alone or follow colors: 1 = single line (default); 2 = double line. Other values raise errors. The real joined CP437 frames use corner/edge codes: single: 218,191,192,217,196,179 double: 201,187,200,188,205,186 Arrows move; Home/End select first/last; PgUp/PgDn move by page; an entry's first character finds the next match. Enter accepts. Mouse click highlights, double-click accepts, wheel moves. Selector mouse events are consumed. Cursor, colors and key repeat are restored; the frame remains on screen, so callers redraw their own view. Example for an 80-column, 25-row screen (double frame): 10 DEFI64 A-Z 20 OPTION BASE 0 30 GETFILES ENTRIES$(),N,"*.TXT" 40 IF N=0 THEN END 50 S=0 60 SELECTBOX 2,2,70,18,30,2,ENTRIES$(),N,S,2 70 IF S>=0 THEN PRINT ENTRIES$(S) Example with colors and a double frame: SELECTBOX 2,2,40,12,36,1,ENTRIES$(),N,S,15,0,0,15,2 BITBLT Syntax: BITBLT slot,x,y[,keyColor] or BITBLT slot,(x,y)[,keyColor] Does: draw bitmap slot 0..65535 at a physical framebuffer position; optional keyColor is transparent Example: BITBLT 0,(100,80),&HFF00FF BMPLOADED / BMPWIDTH / BMPHEIGHT Syntax: BMPLOADED(slot) | BMPWIDTH(slot) | BMPHEIGHT(slot) Does: query whether a LOADBMP slot is present and its dimensions Example: IF BMPLOADED(0) THEN PRINT BMPWIDTH(0),BMPHEIGHT(0) CIRCLE Syntax: CIRCLE [STEP](x,y),radius[,color[,start[,end[,aspect]]]] Does: draw a circle; color is palette 0-15 or packed 0xRRGGBB; start/end/aspect are currently ignored Example: CIRCLE (320,240),100,&HFF8800 DRAW Syntax: DRAW string$ Does: GW Graphics Macro Language (U,D,L,R,E,F,G,H,M,B,N,A,TA,C,S,P); Ppaint,border flood-fills at the current point Example: COL&&=&HFF8800 : DRAW "C=COL&&;R40D40L40U40P=COL&&;,0" GRAMAXX Syntax: GRAMAXX Does: graphics width Example: PRINT GRAMAXX GRAMAXY Syntax: GRAMAXY Does: graphics height Example: PRINT GRAMAXY GRAPITCH Syntax: GRAPITCH Does: framebuffer pixels per row Example: PRINT GRAPITCH GPRINT Syntax: GPRINT [STEP](x,y),text$[,fg[,bg]] Does: draw the existing 8x16 glyphs at an exact graphics coordinate; foreground defaults to the current text color and omitted background is transparent. STEP and VIEW/WINDOW mapping are supported. Example: GPRINT (37,29),"Chart title",15 LINE Syntax: LINE [[STEP](x1,y1)]-[STEP](x2,y2)[,color|r,g,b][,B|BF] or LINE INPUT Does: draw line/box/filled box; graphics color may be palette, packed 0xRRGGBB or RGB triple Example: LINE (10,10)-(200,100),255,136,0,BF LOADBMP Syntax: LOADBMP slot,file$ Does: load an uncompressed 24/32-bit BMP into slot 0..65535 Example: LOADBMP 0,"FOREST.BMP" LOADSPRITE Syntax: LOADSPRITE image,file$[,transparentColor] Does: load sprite image 0..65535 and build its shared opacity mask Example: LOADSPRITE 0,"SPRITES\ALIEN.BMP",&HFF00FF SPRITE Syntax: SPRITE instance,image,(x,y) or SPRITE instance,image,x,y Does: create/reassign/show instance 0..65535 using a loaded image Example: SPRITE 12,0,(100,80) MOVESPRITE Syntax: MOVESPRITE instance,(x,y) or MOVESPRITE instance,x,y Does: move an instance with background restoration; coordinates are physical Example: MOVESPRITE 12,(110,84) SHOWSPRITE Syntax: SHOWSPRITE instance Does: make an existing hidden instance visible Example: SHOWSPRITE 12 HIDESPRITE Syntax: HIDESPRITE instance Does: hide an instance; hidden sprites do not collide Example: HIDESPRITE 12 DELSPRITE Syntax: DELSPRITE instance Does: delete one instance without unloading its shared image Example: DELSPRITE 12 SPRITEOFF Syntax: SPRITEOFF Does: delete all sprite instances at once; loaded sprite images remain available and can be reused by later SPRITE commands Example: SPRITEOFF SPRITETEXT Syntax: SPRITETEXT UNDER | SPRITETEXT OVER Does: UNDER composites sprites over text; OVER redraws text foreground pixels above sprites, useful for HUDs and labels Example: SPRITETEXT OVER SPRITEX Syntax: SPRITEX(instance) Does: physical x coordinate of an existing instance Example: PRINT SPRITEX(12) SPRITEY Syntax: SPRITEY(instance) Does: physical y coordinate of an existing instance Example: PRINT SPRITEY(12) SPRITECOLLIDE Syntax: SPRITECOLLIDE(instance1,instance2) Does: -1 for at least one overlapping pair of opaque source pixels, else 0 Example: IF SPRITECOLLIDE(10,100) THEN PRINT "HIT" SPRITELOADED / SPRITEWIDTH / SPRITEHEIGHT / SPRITEKEYCOLOR Syntax: function(image) Does: query a loaded sprite-image slot, its dimensions and stored key color (-1 if none) Example: IF SPRITELOADED(0) THEN PRINT SPRITEWIDTH(0),SPRITEHEIGHT(0) SAVEBMP Syntax: SAVEBMP file$ [,(x1,y1)-(x2,y2)] Does: save the active graphics VIEW, full screen, or an explicit framebuffer rectangle as an uncompressed 24-bit BMP Example: SAVEBMP "SCREEN.BMP" Example: SAVEBMP "PART.BMP",(100,80)-(399,279) PAINT Syntax: PAINT [STEP](x,y)[,paint|r,g,b[,border]] Does: flood fill; paint accepts palette/packed RGB or an RGB triple; border is palette/packed RGB Example: PAINT (100,100),32,64,128,&HFFFFFF POLYFILL Syntax: POLYFILL (x1,y1),(x2,y2),(x3,y3)[,...][,color|r,g,b] Does: fill a concave or convex polygon with the even-odd rule; STEP vertices are relative to the preceding vertex Example: POLYFILL (20,20),(180,40),(130,160),(40,120),255,136,0 POINT Syntax: POINT(x,y) Does: exact CGA colors return palette 0-15; otherwise returns packed 24-bit 0xRRGGBB; -1 off screen Example: PRINT HEX$(POINT(100,100)) PRESET Syntax: PRESET [STEP](x,y)[,color|r,g,b] Does: set pixel; explicit color accepts palette, packed 0xRRGGBB or RGB triple; default is background Example: PRESET (10,10),255,0,0 PSET Syntax: PSET [STEP](x,y)[,color|r,g,b] Does: set pixel; color accepts palette, packed 0xRRGGBB or RGB triple Example: PSET (10,10),255,136,0 SCREEN Syntax: SCREEN width,height | SCREEN MODE n | SCREEN MODES | SCREEN(row,col) Does: Windows selects a logical framebuffer size; UEFI selects exact GOP dimensions. SCREEN MODES lists physical/display modes. The function form returns the character code stored in a text cell. Example: SCREEN 960,540 Example: PRINT CHR$(SCREEN(10,20)) VIDEOMODE Syntax: VIDEOMODE n,widthVar,heightVar Does: query the width and height of physical/display mode n Example: VIDEOMODE I,W,H SCRNADR Syntax: SCRNADR Does: framebuffer address Example: PRINT HEX$(SCRNADR) VIEW Syntax: VIEW [SCREEN] (x1,y1)-(x2,y2)[,fill[,border]]; VIEW PRINT top TO bottom Does: graphics VIEW clips drawing; fill/border accept palette or packed 0xRRGGBB. The border is one pixel outside the viewport and visible edges are clipped individually at framebuffer boundaries. SCREEN is GW coordinate semantics, not a display page. VIEW PRINT restricts text output/scrolling; LOCATE and CSRLIN still use absolute screen rows. Example: VIEW SCREEN (0,0)-(639,479),&H101820,&HFFFFFF WINDOW Syntax: WINDOW [SCREEN] (x1,y1)-(x2,y2) Does: logical coordinates. SCREEN makes Y increase downward; it is not a display page. Example: WINDOW SCREEN (0,0)-(100,100) MEMORY / SYSTEM --------------- SYSTEMINFO$ Syntax: SYSTEMINFO$(key) Does: return compact support information; keys 0..13 are supported on Windows x64 and x64 UEFI. Unsupported keys return "Unavailable". Keys: 0 Platform and Thoreau BASIC version (3.2) 1 Firmware vendor, where exposed 2 Keyboard layout 3 Keyboard backend and modifier-state availability 4 Storage backend and flush API 5 CPU model/brand exposed by CPUID 6 Usable AVX2 JIT path/SSE2 fallback; UEFI YMM-state information 7 Reported PARFOR capacity, configured cap, last workers used 8 Startup-calibrated TSC counter frequency in MHz 9 Allocated BASIC data/code arena sizes in MiB 10 Pixel dimensions, text grid, pixel pitch and display backend 11 Current JIT ON/OFF setting 12 Compile date/time, compiler and debug/release macro identification 13 CPU vendor/family/model/stepping, hypervisor and invariant-TSC flags PARFOR capacity includes the caller/BSP and is capped at 32. Actual workers can be fewer; OPTION PARTHREADS 0 is automatic. AVX2 denotes a usable path, not use by every operation or that JIT is ON. TSC MHz is g_tsc_hz from startup OScalibrate_tsc(), displayed to three decimals. It is a counter rate, not live CPU clock/throughput; the query does not recalibrate. Arena sizes are allocated capacities, not installed RAM/free memory; use FRE for live available memory. CPU data reflects the host/hypervisor-visible CPUID information. NDEBUG identifies a build macro, not proof of optimization flags. MOUSEINFO, NETINFO and SOUND INFO remain separate detailed queries. Example: FOR I=0 TO 13:PRINT SYSTEMINFO$(I):NEXT BATTERYPERCENT Syntax: BATTERYPERCENT(0) Does: return 0..100 when the OS/firmware supplies a battery percentage, or -1 when absent/unknown. Windows uses GetSystemPowerStatus; UEFI queries the EFI Battery Charging Protocol when available. A reading is not inferred when the protocol/device is unavailable. Example: B=BATTERYPERCENT(0):IF B>=0 THEN PRINT B;"%" SYSTEM Syntax: SYSTEM Does: leave Thoreau BASIC; Windows closes the application; UEFI returns to the firmware/caller Example: SYSTEM KEYB Syntax: KEYB [xx] Does: UEFI only: show or switch the current keyboard layout; THOREAU.CFG beside the EFI accepts KEYB xx at startup; default is US Layouts: BE BR DK GR SU FR UK IT YU CF LA NL NO PL PO SV SG SF SP SL CZ HU US Example: KEYB GR THOREAU Syntax: THOREAU Does: enter DebuggerMode; STATE, STACK, FLOW, BREAKS, TIMERS and INTERNALS inspect the live interpreter; X restores the prior display/settings; THOREAU LANDMARKS, MEMMAP or INFO provides direct views Example: THOREAU THOREAUADR Syntax: THOREAUADR(name$) Does: 64-bit address of a named machine landmark Example: PRINT HEX$(THOREAUADR("FRAMEBUFFER")) DATE$ Syntax: DATE$ Does: current date Example: PRINT DATE$ FREEBOT Syntax: FREEBOT Does: bottom of free data memory Example: PRINT FREEBOT FREETOP Syntax: FREETOP Does: top of free data memory Example: PRINT FREETOP FRE Syntax: FRE(x) Does: free BASIC data bytes, including reusable blocks returned by ERASE/bitmap replacement Example: PRINT FRE(0) HIMEM Syntax: HIMEM Does: high memory address Example: PRINT HIMEM LOMEM Syntax: LOMEM Does: low memory address Example: PRINT LOMEM PEEK Syntax: PEEK(address) Does: read byte at 64-bit address Example: PRINT PEEK(HIMEM-1) POKE Syntax: POKE address,byte Example: POKE LOMEM,255 PEEK16 Syntax: PEEK16(address) Does: read unsigned 16-bit little-endian value Example: PRINT PEEK16(LOMEM) PEEK32 Syntax: PEEK32(address) Does: read unsigned 32-bit little-endian value Example: PRINT PEEK32(LOMEM) PEEK64 Syntax: PEEK64(address) Does: read raw 64-bit little-endian value as && Example: PRINT PEEK64(LOMEM) POKE16 Syntax: POKE16 address,value Does: write 16-bit little-endian value Example: POKE16 LOMEM,4660 POKE32 Syntax: POKE32 address,value Does: write 32-bit little-endian value Example: POKE32 LOMEM,&H12345678 POKE64 Syntax: POKE64 address,value Does: write all 64 bits of an && value Example: POKE64 LOMEM,123456789&& TIME$ Syntax: TIME$ Does: current time Example: PRINT TIME$ TIMER Syntax: TIMER Does: seconds since boot; TIMER(n) returns interval ms; TIMER(n)=ms sets; TIMER(n) ON/OFF controls timer n Example: TIMER(0)=1000 : ON TIMER(0) GOSUB 9000 : TIMER(0) ON WAITREL Syntax: WAITREL milliseconds Does: relative frame pacing; waits only for the remaining time since the previous WAITREL returned; late frames return immediately and re-anchor instead of catching up Example: WAITREL 16 ECONOMY Syntax: ECONOMY Does: detailed memory accounting for source/token cache, variables, arrays, strings, bitmaps/sprites, display buffers, fixed runtime tables and BASIC-arena free space Example: ECONOMY COMMANDLINEARG$ Syntax: COMMANDLINEARG$(n) Does: 1-based command-line argument after the autostart program; empty string if absent Platform: Windows only Example: PRINT COMMANDLINEARG$(1) COMMANDLINECOUNT Syntax: COMMANDLINECOUNT Does: number of arguments available through COMMANDLINEARG$ Platform: Windows Example: PRINT COMMANDLINECOUNT ENVIRON$ Syntax: ENVIRON$(name$|n) Does: Windows process environment. name$ returns the exact named value; n=1..255 returns the nth KEY=value entry; text is converted to BASIC CP437 and absent entries return an empty string. Platform: Windows only Example: PRINT ENVIRON$("PATH") STARTUP.BAS Syntax: STARTUP.BAS Does: UEFI startup program automatically loaded and run when no explicit autostart program is supplied Platform: UEFI interpreter startup feature Example: Create STARTUP.BAS containing: LOAD "MENU" : RUN OPERATORS / SYNTAX WORDS ------------------------ AND Syntax: AND Does: bitwise/logical conjunction Example: IF A AND B THEN PRINT "both" BASE Syntax: BASE Does: used by OPTION BASE Example: OPTION BASE 1 BREAK Syntax: BREAK [LIST] lists breakpoints; BREAK line[,line...] sets; BREAK DELETE line removes; BREAK CLEAR clears. ON BREAK GOTO remains supported Example: BREAK 1000,2000 ELSE Syntax: ELSE Does: alternate IF branch Example: IF A=1 THEN PRINT "one" ELSE PRINT "other" EQV Syntax: EQV Does: logical equivalence Example: PRINT A EQV B IMP Syntax: IMP Does: logical implication Example: PRINT A IMP B LET Syntax: LET variable=expression Example: LET A=42 MOD Syntax: MOD Does: integer remainder Example: PRINT 17 MOD 5 NOT Syntax: NOT Does: bitwise/logical negation Example: PRINT NOT 0 OR Syntax: OR Does: bitwise/logical disjunction Example: IF A OR B THEN PRINT "yes" RANDOMIZE Syntax: RANDOMIZE [seed] Example: RANDOMIZE TIMER STEP Syntax: STEP Does: FOR increment or relative graphics point Example: FOR X=0 TO 100 STEP 5 ON TIMER Syntax: ON TIMER(n) GOSUB line Does: bind timer n (0..7) to a GOSUB handler Example: ON TIMER(0) GOSUB 9000 ON MOUSEMOVE Syntax: ON MOUSEMOVE GOSUB line Does: dispatch coalesced pointer movement between BASIC statements, up to about 200 Hz Example: ON MOUSEMOVE GOSUB 9000 ON MOUSECLICK Syntax: ON MOUSECLICK GOSUB line Does: queue button-down edges; MOUSEX/Y/B in the handler report the captured click snapshot Example: ON MOUSECLICK GOSUB 9100 ON MOUSEDOUBLECLICK Syntax: ON MOUSEDOUBLECLICK GOSUB line Does: dispatch two clicks of the same button within 500 ms and 16 pixels; MOUSEDBLCLICK is an alias Example: ON MOUSEDOUBLECLICK GOSUB 9200 THEN Syntax: THEN Does: IF consequence Example: IF READY THEN GOTO 1000 TO Syntax: TO Does: FOR/VIEW PRINT range word Example: FOR I=1 TO 10 USING Syntax: USING Does: PRINT formatting word Example: PRINT USING "###.##";X XOR Syntax: XOR Does: bitwise/logical exclusive OR Example: PRINT A XOR B THOREAU MACHINE EXPLORER ======================== Enter it from BASIC with: THOREAU F12 enters the same protected DebuggerMode from the BASIC prompt, during INPUT, or while a program is running. The debugger starts on a cleared screen with normal key repeat and sprites temporarily hidden. X returns to the prompt or resumes the interrupted program after restoring the framebuffer, text grid, cursor, colors, text/graphics views, sprite presentation and KEYREPEAT settings. Numbers in the monitor are hexadecimal by default. Prefix a decimal value with D:, for example D:4096. Core monitor commands: STATE Summarize execution state, current/continuation locations, last pause or error, program/variable/file/stack counts, breakpoints, timers and tracing. STACK Show the live GOSUB and programmable-timer call stack, newest frame first. FLOW Show FOR, WHILE, ERROR/BREAK handler and single-line IF control frames. BREAKS Show the last pause, CONT target and active source-line breakpoints. TIMERS Show every configured programmable timer, handler, deadline and state. INTERNALS Show addresses and capacities of the interpreter's principal structures. L Show named machine/interpreter landmarks. Example: L M [address [length]] Hex/ASCII memory dump. M alone continues from the previous dump. Example: M LOMEM 100 M! address [length] UEFI only: force a read of a normally refused/protected region. Windows deliberately does not provide forced protected reads. Example: M! 100000 100 F start end byte Fill memory. Example: F 100000 1000FF 00 C start1 end1 start2 Compare two memory blocks. Example: C 100000 1000FF 200000 > address hex... Enter hexadecimal bytes. Example: > 100000 48 65 6C 6C 6F A address text... Enter ASCII bytes. Example: A 100000 HELLO H start end hex... Hunt for a hexadecimal byte sequence. Example: H 100000 110000 DE AD BE EF HA start end text... Hunt for ASCII text. Example: HA 100000 110000 THOREAU T start end dest Transfer/copy memory. Example: T 100000 1000FF 200000 SAVE file start end Save raw memory to a file. Example: SAVE dump.bin 100000 100FFF LOAD file address Load a raw file into memory. Example: LOAD dump.bin 200000 R address Describe the containing memory region. Example: R LOMEM W address Show nearest landmark and containing region. Example: W FRAMEBUFFER V address View BYTE/WORD/DWORD/QWORD and typed interpretations. Example: V LOMEM MAP Show the platform memory map. Example: MAP I Show compact machine information. Example: I Read-only storage / boot inspection: DISKS Enumerate disks / whole-media devices. Example: DISKS DISK n Show disk/media details. Example: DISK 0 SECTOR n lba [count] Dump raw sectors as hex/ASCII. Example: SECTOR 0 0 1 PARTITIONS n Show GPT/MBR partition information. Example: PARTITIONS 0 PARTITION n p Show one partition in detail. Example: PARTITION 0 1 VOLUMES Enumerate mounted/accessible filesystems. Example: VOLUMES DIRFS v [path] List a directory on a selected volume. Example: DIRFS 0 \EFI\BOOT CAT v file Display a file as text. Example: CAT 0 \STARTUP.NSH HEXFILE v file Display a file as hex/ASCII. Example: HEXFILE 0 \EFI\BOOT\BOOTX64.EFI BOOT Inspect UEFI BootOrder / Boot#### information where available. Example: BOOT OS Best-effort installed operating-system detection. Example: OS ? or HELP Show monitor help. X Return to BASIC. NOTES ===== - BASIC source files are ASCII text with line numbers. - CREATEEXE / CREATEEFI embed the currently loaded BASIC program and, by default, an available GM wavetable. Add NOGM to omit the wavetable. Other external data files are not embedded; keep BMPs, save files, audio files and other runtime assets alongside the application as required by the program. - CREATEEXE and CREATEEFI are direct-mode commands and require a program to be loaded. - The UEFI build and Windows build share the language core, but a few startup and platform commands differ as documented above. - UEFI keyboard layout configuration is stored in THOREAU.CFG beside the EFI. Windows keyboard input remains native to Windows and ignores this file. - SYSTEM is portable BASIC source: it exits the Windows application or returns the UEFI application to its firmware/caller. - Thoreau BASIC is free to use. Support development: paypal.me/gatesofintegrity Website: https://thoreaubasic.com