THOREAU BASIC 3.4.1 =================== 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.4.1 corrects false AUDIT warnings for comparisons with INKEY$, CLIPBOARD$, DATE$, TIME$, ERROR$ and other built-in names. Genuine conflicting scalar assignments still produce warnings. Both TXTWINDOW forms and SELECTBOX use row,column text positions, retaining the latest 3.4 coordinate update. Version 3.4 introduced runtime expressions and indirect variable access, file attributes and Windows drive queries, resumable ACCEPT forms and UEFI display rotation. Keyboard shortcuts reach INKEY$ more consistently; SELECTBOX has proper scroll arrows. These features, the additional AUDIT checks and the improved runtime error reporting remain available in 3.4.1. Important for existing programs: older column-first SELECTBOX calls need their first two arguments swapped. Older column-first TXTWINDOW calls need each coordinate pair swapped, including the @n form. Programs already using the row-first 3.4 updates must not swap them again. The 37-character identifier base-name limit remains enforced. VERSION 3.4.1 CHANGES describes this update; VERSION 3.4 CHANGES retains the history since the original 3.3 release. Version 3.3 adds automatic SSE2/AVX2 loop packets for eligible independent calculations, including counted and hypercomplex fractal paths. Scalar JIT work reduces arithmetic error-path overhead, reuses exact expressions and accelerates eligible variable-integer powers. Arithmetic order is retained. 3.3 also adds ACCEPT field input, CONT NEXT statement stepping, logical wrapped command editing, sprite-preserving pauses, syntax-only AUDIT checks and stricter END validation. SELECTBOX gains titles, menu-key/click outputs, single-click acceptance, separators and right-click cancellation. LINE supports XOR, LIST NOWAIT can be interrupted, and BEEP/BEL has a bank-independent console tone. This manual describes version 3.4.1. Earlier introductions and VERSION sections retain release history; the current command reference takes precedence. Version 3.4 supersedes the earlier SELECTBOX and TXTWINDOW coordinate orders and extends ACCEPT input. Version 3.3 superseded the old SELECTBOX click behavior and historical UEFI BEL description; 3.2 superseded uppercase directory display and case-insensitive file-mask matching. 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. 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. Version 3.0 also improves performance in programs with supported error/event handlers, sprite drawing, repeated sound settings and source loading. Normal numeric behavior, sound quality and error handling are retained. 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 can reuse parallel workers during a running program, reducing the cost of repeated loops. Supported processors can use AVX2 even when firmware did not enable the required processor state. Startup reports SIMD and framebuffer capabilities, and graphics PUT ...,PSET can present large images more quickly. 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 and supported UEFI firmware share independent iterations among workers. Numeric and @ scalars are private to each worker; suitable independent array and framebuffer writes provide shared output. 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.4.1 CHANGES ===================== Release date: 14 October 2026 Previous numbered release: 3.4, 13 October 2026 Version 3.4.1 is a maintenance release collecting the AUDIT correction and row,column TXTWINDOW update previously distributed in updated 3.4 packages. Programs already using those updates need no further coordinate changes. The other language features and platform requirements of 3.4 are unchanged. AUDIT CORRECTION ---------------- - Comparisons with INKEY$, CLIPBOARD$, DATE$, TIME$, ERROR$ and other built-in names no longer produce false scalar/function-name warnings. This includes comparisons in IF and WHILE conditions, PRINT expressions, assignment right-hand sides and function arguments. - Warnings remain enabled for actual scalar assignments that share function names, including LET, FOR/PARFOR counters and THEN/ELSE assignments. Existing array-name checks remain enabled. AUDIT still checks without running the program or consuming keyboard input. TEXT COORDINATES AND COMPATIBILITY --------------------------------- - Both TXTWINDOW forms use row,column pairs: TXTWINDOW row1,column1,row2,column2 TXTWINDOW @n,row1,column1,row2,column2 Corners are 1-based, inclusive positions on the whole-screen text grid. This retains the correction supplied in the latest 3.4 update. - When upgrading from a build with column-first TXTWINDOW, swap each coordinate pair and leave the @n window number in place. There is no automatic recognition of the old order. Programs already using row-first TXTWINDOW must not swap their arguments again. - SELECTBOX retains the row,column position introduced in 3.4. Calls from before that change need their first two arguments swapped. Its width,height dimensions and clickX,clickY pixel outputs keep their existing order. - LOCATE, ACCEPT AT and SCREEN(row,column) remain row-first. TXTWINDOW's window-relative cursor behavior is unchanged. Bare TXTWINDOW still removes only the default region; named windows and VIEW PRINT remain in effect. Graphics and mouse coordinates remain x,y, not row,column text cells. UPGRADING --------- - Windows and UEFI identify this release as 3.4.1 in their version displays, built-in HELP and system information. - Re-create standalone EXE/EFI applications with 3.4.1 to include these fixes. Replacing the interpreter does not update applications already created. - Runtime expressions, indirect variables, ACCEPT forms, file and drive queries, UEFI rotation, keyboard fixes and other 3.4 features are retained. The 3.4 history below documents those cumulative changes since 3.3. VERSION 3.4 CHANGES =================== This history includes the follow-up TXTWINDOW and AUDIT updates distributed under 3.4 before they were collected in 3.4.1. Release date: 13 October 2026 Previous release: 3.3, 11 October 2026 Version 3.4 collects the changes made after the original 3.3 release of 11 October 2026. It adds runtime expressions, indirect variable access, filesystem queries, resumable form input and UEFI display rotation, together with keyboard, menu, syntax and error-reporting improvements. COMPATIBILITY NOTES ------------------- - SELECTBOX now starts with row,column rather than column,row. Swap the first two arguments in older calls. There is no compatibility mode. All remaining arguments keep their order; mouse outputs remain clickX,clickY in pixels. - TXTWINDOW now uses row1,column1,row2,column2 for both the default region and the named @n form. Swap each coordinate pair in older calls; leave the window number in place. Both corners use 1-based, inclusive screen text cells. There is no old-order mode. Bare TXTWINDOW still restores ordinary full-screen output subject to VIEW PRINT; window-relative LOCATE behavior is unchanged. Text positions now consistently use row,column in LOCATE, ACCEPT AT, SCREEN(row,column), SELECTBOX and TXTWINDOW. Graphics remain x,y. - Identifier base names remain limited to 37 characters, excluding the type suffix. Longer names now raise an error instead of being silently shortened. - Re-create standalone EXE/EFI applications to include the 3.4 changes. KEYBOARD SHORTCUTS AND MENUS --------------------------- - On Windows, Alt+printable keys and previously silent Ctrl+digit or Ctrl+punctuation combinations now produce INKEY$ character events. The returned character follows the active layout, Shift and Caps Lock without adding a special modifier prefix. Pressing a modifier alone stays silent. - Ctrl+A through Ctrl+Z retain character codes 1..26. Supported function and navigation keys retain their existing two-byte INKEY$ results. Duplicate delivery of control characters, including Ctrl+H, Ctrl+I and Ctrl+M, is fixed. - Repeated application Alt shortcuts no longer trigger the unwanted Windows menu beep. Alt+Space still opens the system menu. Alt+F4, Alt+Tab, Alt+Escape, Windows-key shortcuts and Alt+numpad entry remain Windows-owned. AltGr text entry is preserved. F11/Alt+Enter remain fullscreen controls and F12 remains the debugger rather than an ordinary application key. - Custom KEYREPEAT timing applies to the new shortcut events. Releasing the key or leaving the application stops its repeat. KEYDOWN remains a live held-state query, not a saved modifier snapshot for an earlier INKEY$ event. - SELECTBOX uses CP437 CHR$(24) and CHR$(25) for its up/down scroll arrows in both frame styles. Menu-mode key$ can return the newly delivered shortcuts. - UEFI firmware input remains limited to keys and modifiers actually supplied by the firmware; the update cannot recover events a device never reports. ACCEPT FORMS AND RESTART ----------------------- - A comma or semicolon may separate ACCEPT options from the destination. The previous colon separator remains valid. Optional key$ and paired clickX,clickY outputs enable form input. - Form input can return on Enter, Tab, Shift+Tab, Up/Down, Page Up/Down, delivered function keys and shortcuts not used by the field editor. Tab returns CHR$(9); Shift+Tab returns CHR$(0)+CHR$(15). Existing selection, clipboard and other editing shortcuts continue to edit the field. - A left click inside the field positions the caret. An outside left click returns key$="MOUSE" and optional pixel coordinates. Escape or right-click returns CHR$(27) without changing the destination or invoking ON BREAK. Keyboard and cancellation returns set optional click coordinates to -1,-1. - Other form exits validate and commit the value. Malformed numeric text remains editable; overflow is an ordinary BASIC error. Form exits do not force a newline. Without key$, ordinary Enter/Escape and ON BREAK behavior remains unchanged. - Delivered Alt+character and Ctrl+printable shortcuts return to the form's caller rather than inserting text. AltGr printable input remains text. - RESTART restores the last yielded field's draft, caret, selection, horizontal position, insert/overwrite mode and one-level undo/redo state when the same ACCEPT statement, destination, options and geometry match. It requires key$ output. A first use or mismatch starts normal input. - Only the last yielded field is retained. Enter completes it; opening another field replaces it. RUN, NEW and CLEAR clear the saved state. A matching RESTART uses the saved draft, not a value subsequently assigned by the caller. To display that new value, start fresh with DEFAULT instead. FILES AND WINDOWS DRIVES ------------------------ - GETFILES adds an optional final skipped-count output: GETFILES names$(),count[,filespec$[,flags[,skipped]]] Supplying skipped lets a listing return representable names while counting eligible names that cannot be represented in BASIC. Without it, such a name remains an error. Supply filespec$ and flags to reach the skipped argument. - File masks are applied before filename conversion, so unrelated files with unrepresentable names no longer interrupt a listing. Included directories still bypass the file mask. Other errors and cancellation leave the old destination array and output values unchanged, rather than returning a partial successful result. Windows filenames remain CP437; UEFI filenames remain ASCII. No lossy replacement names are returned. - FILEATTR(path$) reads file/directory attributes on both platforms: 1 read-only, 2 hidden, 4 system, 16 directory and 32 archive. Normal attributes return 0; an unavailable query returns -1. Check for -1 before testing attribute bits. - Windows GETDRIVES roots$(),count returns drive-letter roots in alphabetical order. DRIVETYPE(root$) reports unknown, absent, removable, fixed, network, optical or RAM-disk classification. DRIVEPATH$(root$) returns a mapped network resource, or an empty string when no mapping is available. - Drive queries do not promise that media is ready or accessible. These three facilities are Windows-only; FILEATTR and GETFILES also work on UEFI. RUNTIME EXPRESSIONS AND INDIRECT VARIABLES ----------------------------------------- - EVAL(expr$) evaluates one complete expression held in a string, using current variables, arrays, functions and DEF FN definitions. Numeric, string and hypercomplex result types are preserved. Errors use the calling program's normal ERR, ERL, ERROR$ and ON ERROR handling. - EVAL accepts up to 4,095 bytes, 127 expression tokens and 16 nested EVAL calls, subject to the ordinary expression and function nesting limits. Statements, comments outside strings, embedded NUL/newlines and malformed expressions are rejected. It is not a general command-execution facility or a sandbox for untrusted input: called functions can have side effects. - GETVAR(name$[,indices...]) reads a scalar or existing array element by name. A missing scalar returns its typed zero or empty value without declaring it. Missing arrays, incorrect dimensions and out-of-range subscripts are errors. - SETVAR value,name$[,indices...] assigns indirectly with normal type conversion, creating a missing scalar when necessary. DCLVAL name$[,bounds...] declares a new scalar or an array with one to four dimensions. Duplicate declarations are errors. Arrays are not automatically created or enlarged by an indirect assignment, and runtime values such as ERR are excluded. - EVAL and indirect variable access work with JIT ON but are not available inside PARFOR. AUDIT reports PARFOR checks involving hidden dynamic dependencies as incomplete rather than claiming those dependencies are safe. IDENTIFIER SPELLING ------------------- - Names may begin with an underscore and contain underscores. They remain case-insensitive and retain the ordinary type suffixes. An underscore has no special meaning for scope or access. - An unsuffixed name beginning with underscore defaults to DOUBLE; DEFxxx letter ranges continue to apply to A-Z. Use a suffix for another type. FIND/REPLACE WORD, XREF, AUDIT, RENUM, DRAW substitutions and state schemas recognize the same identifier spelling. AUDIT, PARFOR AND ERROR REPORTING -------------------------------- - AUDIT no longer mistakes comparisons with INKEY$, CLIPBOARD$, DATE$, TIME$, ERROR$ or other built-in names for scalar assignments. Function-name warnings apply to actual assignment targets, including LET, FOR/PARFOR counters and assignments in THEN/ELSE branches. Genuine scalar/function-name conflicts and the existing array-name checks remain enabled. - AUDIT warns about possible unintended scalar accumulation inside PARFOR, identifying the variable, source location and enclosing loop. It considers assignments, branches and nested loops without running the program. Unsupported or ambiguous cases are reported as skipped or incomplete. - PARFOR scalar behavior is now explicit in the reference: numeric and hypercomplex scalars are private to each worker, not freshly reset for each iteration. Final private scalar values are not copied back, even with one worker, and there is no automatic sum or other reduction. This clarifies existing behavior; the new AUDIT warning does not change execution rules. - AUDIT accepts empty THEN and ELSE branches, matching program execution. Conditions and nonempty branches are still checked. IF ... GOTO still requires a target; nested ELSE binding is unchanged. - LOCATE now rejects semicolons and invalid trailing text consistently in direct mode and stored programs, with JIT either on or off, including named text windows. Errors can be trapped and RESUME NEXT continues normally. Valid omitted coordinates and legacy comma-separated extra fields remain accepted; a malformed LOCATE does not apply a partial cursor movement. - With JIT ON, malformed text on a later line no longer stops an earlier valid statement or gives that earlier line as the error location. An undefined jump target is reported at the jump; malformed text at an existing target is reported at that target when it is reached. UEFI DISPLAY ROTATION --------------------- - THOREAU.CFG beside the EFI accepts ROTATE = 0, 90, 180 or 270, in clockwise degrees. The default is 0. The setting can appear before or after KEYB. Change the file and restart the EFI to apply a new orientation. - Quarter turns swap logical screen width and height. SCREEN, mode queries, text, graphics, sprites, menus and the debugger use the rotated logical screen. Existing mode indices remain unchanged; no new physical modes are added. BASIC graphics and saved images keep their normal logical orientation. - Mouse positions and click outputs remain logical pixels. Relative movement is unchanged. Absolute input assumes panel-native firmware coordinates; device-specific touch orientation may need checking on the actual hardware. - Rotation also applies to newly created standalone EFI applications using their adjacent configuration file. Startup and SYSTEMINFO$(10) report the orientation and logical/native dimensions; ECONOMY includes display memory. - Rotation needs additional memory and display processing. It does not rotate firmware setup screens, early firmware text or the Windows desktop. Invalid settings produce a warning and disable rotation. See the manual for the configuration rules, memory requirements and hardware limitations. VERSION 3.3 CHANGES =================== NATIVE LOOP SIMD - Eligible independent FOR calculations can process four iterations together with usable AVX2, or two with SSE2, without new BASIC syntax. Each iteration retains its own branches and escape time; array access and drawing remain in their original order. Eligible calculations can also run within PARFOR. - The outer FOR variable must be DOUBLE, with an exactly representable integral current value and positive integral STEP. Fractional limits are allowed when they select the same iterations. Short tails, dependencies, unsupported effects and exceptional cases retain ordinary scalar execution. - Tracing, profiling and active handlers can limit which paths are accelerated. COUNTED AND HYPERCOMPLEX CALCULATIONS - Eligible calculation sections can include up to eight contained inner FOR/NEXT loops with DOUBLE counters. Supported inner steps and limits can be positive, negative, fractional or different between outer iterations. - Eligible complex, quaternion and octonion calculations support constructors, matching-dimension arithmetic, real scaling, conjugation, component reads and norms. Arithmetic order and normal exceptional-case handling remain. - Plain counted numeric loops stay scalar on SSE2 by default; eligible hypercomplex calculations can still use the two-iteration SSE2 path. SCALAR JIT OPTIMIZATIONS - Eligible comparisons, DOUBLE arithmetic and square roots need less overhead. Exact repeated expressions can reuse their previous result without changing operation order, types or the position of the first calculation. - Eligible DOUBLE bases with exact positive variable-integer exponents from 1 through 65536 have an accelerated path. Zero bases, other exponent types and exceptional results retain normal behavior. Literal integer powers keep their existing optimization. - These changes do not reduce precision or rearrange arithmetic. See NATIVE EXECUTION for the current coverage and limits. COMMAND EDITOR AND LIST - Direct command entry and EDIT retain one logical input buffer across visual line wraps and scrolling. Enter submits the complete logical line; Home and End address that line. No underscore continuation is required. - EDIT primes its input from the stored source rather than reconstructing only the visible screen fragment. Wrapped-row spaces and off-screen prefixes are retained. Existing limits remain 255 typed bytes and 244 stored program-body bytes. - Repainting clears deleted text without blanking untouched graphics after the text or on an otherwise empty Ready cursor row. - LIST NOWAIT polls Escape between source lines. NOWAIT disables paging, not cancellation. Escape arriving between the pager's break and key polls also cancels instead of advancing. Captured listings stay non-interactive; cancelling LIST does not destroy a paused program's continuation/sprites. ACCEPT FIELD INPUT - ACCEPT adds a bounded, single-row field editor for a string or numeric destination. The option form accepts AT(row,col), SIZE(n), VALIDATE(...), BEEP, DEFAULT and UCASE or LCASE before an internal colon and destination. Options may be reordered; duplicate/conflicting options are rejected. - SIZE permits 1..255 bytes; a field wider than the available display space scrolls horizontally. Without SIZE, capacity is the remaining text-row width, capped at 255. AT uses LOCATE-style coordinates and suppresses the final newline; without AT, input begins at the current text cursor. - VALIDATE accepts character-set strings with ranges, named sets DIGIT, NUMERIC, UALPHA and ALPHA, or comma-separated combinations. It filters characters; a numeric destination is still parsed and range-checked when Enter commits. DEFAULT edits the current value. UCASE/LCASE converts case before filtering. The BEEP option sounds on entry. - Shift+Left/Right/Home/End selects text. Ctrl+A/C/X/V/Z selects all, copies, cuts, pastes and undoes. Ctrl+Insert, Shift+Delete and Shift+Insert provide copy/cut/paste alternatives. Insert toggles insert/overwrite mode. - Pasted text is filtered and cannot execute commands or submit the field. Rejected characters do not delete an existing selection. Malformed numeric input remains editable; overflow remains a BASIC error. - Escape leaves the destination unchanged and follows normal ON BREAK handling. F12 can open the protected debugger. Windows and raw-HID UEFI capture navigation modifiers with the key event; firmware-only UEFI input remains limited by the key/modifier information the firmware supplies. - The colon between ACCEPT options and its destination belongs to that statement; a later colon separates statements normally. Option words are contextual, not globally reserved BASIC keywords. CONT NEXT AND SPRITE PAUSES - CONT NEXT resumes a saved continuation for one statement, then pauses before the next. It steps inside inline IF branches and into GOSUB rather than allowing a whole native region to run ahead. A PARFOR executes as one atomic statement for stepping. - Single stepping does not toggle the user's JIT setting or flush JIT caches. Timer/mouse callbacks are deferred during the step. Inline-IF continuation context is saved separately from direct-mode inspection, so CONT resumes the selected branch rather than entering its ELSE arm. - Sprite instances survive resumable STOP, Escape and breakpoint pauses. Their overlay is hidden at the prompt and restored by CONT, retaining IDs, positions, visibility and order. Actual termination and invalidated/reset program state still perform normal instance cleanup. - The Machine Explorer recognizes a single-step pause; the paused source position becomes the current edit-line reference. SYNTAX, AUDIT AND LOOP EXITS - A string literal may end implicitly at the physical source-line terminator in any statement. Colons, apostrophes and REM inside an open string remain string data. Missing parentheses are not supplied, and separate source-file lines are not joined. Visual editor wrapping is a different mechanism. - AUDIT performs a syntax-only phase without executing statements, evaluating expressions, calling DEF FN bodies or creating program variables. It checks malformed core syntax and expressions, assignments, control flow, ACCEPT and delimiters, including unreachable branches, with source locations. - Specialized argument grammars not fully parsed by this phase are explicitly reported as name/delimiter-only checks. AUDIT is not a claim of complete semantic validation or proof that a program will run without errors. - Structural auditing counts PARFOR openings, does not mistake OPEN ... FOR for a loop, and does not treat CONT NEXT or RESUME NEXT as closing a FOR. Existing literal-target, function-name and loop-order checks remain. - END now rejects trailing tokens instead of silently ending the program. END FOR is a syntax error, not an alias for FOR END. The interpreter, native-region compiler and AUDIT use the same boundary rule. Normal colons, inline ELSE boundaries and apostrophe comments remain valid terminators. - FOR END and WHILE END exit the intended loop under JIT execution rather than being mistaken for whole-program termination. SELECTBOX MENUS - SELECTBOX accepts an optional title string drawn in its top frame. The title is clipped without overwriting corners or scroll indicators. - An optional scalar key$ output enables menu mode. Enter or an accepted mouse click returns CHR$(13); Escape/right-click returns CHR$(27). Other non-navigation keys return their INKEY$ bytes and the current choice. Left/Right in a one-column menu returns control to the caller. - An outside left-click in menu mode returns key$="MOUSE" and the current choice. Optional paired numeric scalar clickX,clickY outputs preserve the queued accepted/outside click's framebuffer pixel coordinates. Keyboard, cancellation and empty-list results return -1,-1 for those outputs. - A single left-click now accepts an item; double-click is no longer required. Escape or right-click cancels with choice=-1. Pending selector mouse events are consumed so they do not leak into the caller. - Optional trailing SEPARATORS, without a preceding comma, turns an item exactly "-" into an unselectable horizontal rule. One-column rules join the frame; multi-column rules fill their slot. Navigation and first-letter matching skip rules; clicking a rule leaves the selector open. - Separator slots remain part of count and actual array indices. An initial separator searches forward, then backward for a selectable item. Empty or all-separator lists return choice=-1, an empty key$ and -1,-1 coordinates. Without SEPARATORS, a literal "-" remains ordinary selectable text. LINE XOR AND PARFOR DIAGNOSTICS - LINE accepts the final XOR drawing modifier for lines, rectangle outlines and filled rectangles, with palette/packed RGB or component colors. STEP, WINDOW/VIEW and clipping continue to use the existing coordinate rules. - XOR combines the low 24 color bits with the sprite-free drawing surface. Repeating the same geometry and color restores the original pixels. Box corners and degenerate lines are handled without duplicate XOR toggles. - Interpreter and ordinary JIT/FOR execution support LINE XOR. PARFOR rejects it with a specific diagnostic because it reads and modifies existing pixels rather than performing an independent overwrite. Graphics PUT's existing XOR behavior and the numeric XOR operator are unchanged. - PARFOR diagnostics distinguish a nonzero ON BREAK target, active interpreter IF context and incompatible timer/mouse-handler configurations. ON BREAK GOTO 0 removes only the custom break handler and that restriction; it does not disable Escape or ON ERROR. ON ERROR GOTO 0 is not a substitute. This documents the handler binding accurately, not a new no-break mode. BEEP / BEL - BEEP and screen PRINT CHR$(7) now use a private built-in 800 Hz, 200 ms tone which does not load or require a GM wavetable or consume a note voice. - Short attack/release ramps avoid abrupt edges; repeated BEL extends the tone while preserving phase/gain. Instrument-channel controls do not alter this console tone. - Windows uses the PCM path with an OS Beep fallback rather than relying on notification-sound configuration. UEFI needs an available supported HDA output path; a bank-free beep does not imply audio hardware is optional. 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. Repeated RUN inside a stored program can restart indefinitely without exhausting stack space. Escape still interrupts. 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. 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 and finishes loading before playback begins. SOUND INFO reports load timing, worker counts and status. - UEFI Opus loading is faster and its decoding fix was 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 ------------------------------ - ON ERROR, timer handlers and mouse handlers can coexist with eligible accelerated calculations. Errors and events retain the correct BASIC line and control-flow context. Unsupported combinations use normal execution. - ON BREAK and other restrictions still apply; see the current JIT and PARFOR references rather than assuming every handler/loop combination is eligible. SPRITE DRAWING -------------- - Small graphics changes while sprites are visible can update only the affected area, reducing the work needed for animation. Screen changes and other cases that require it still refresh the complete display. SOUND PROCESSING ---------------- - Repeated instrument and MIDI settings require less processing when their exact inputs remain unchanged. This does not reduce sound quality. LOADING AND MERGING PROGRAMS ---------------------------- - LOAD, MERGE and CHAIN avoid repeated preparation during a source import. A partial import error leaves the successfully loaded prefix and runtime state consistent. 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 calculations can share work without changing their results. Large integer loops, scalar arithmetic and one-dimensional numeric array access have faster native execution paths. - Integer FOR/NEXT and simple FOR-indexed array assignments perform less repeated work. Type conversion, numeric overflow, array bounds and normal BASIC errors retain their existing behavior. - Long-running loops remain responsive to interruption and events. - 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 conversion as CLIPBOARD$, and typed Windows Unicode characters are converted to CP437. 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 crashing Thoreau through uncontrolled recursion. 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 ------------------------ - Repeated DOUBLE calculations, GOSUB-heavy programs, PARFOR calls and one-dimensional numeric array access perform less repeated work. - Eligible DOUBLE FOR loops with exact-integer values have faster counting while preserving their DOUBLE type. Other loops keep ordinary behavior. - Errors in accelerated calculations retain their actual BASIC source line. Break and abort handling remain responsive during parallel work. 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; sampled CPU time remains available without exact execution counts. - 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 -------------------------- - Text, glyph output, scrolling and bulk graphics are faster. Long-running calculations present graphics progressively instead of waiting until the program finishes. - Alternative firmware display paths improve responsiveness where direct framebuffer output is slow. Input waits, HELP and the end of RUN present pending graphics before continuing. - Keyboard/mouse polling and a stationary pointer need less repeated work. 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 loops reuse previous preparation rather than continually consuming more program memory. A fresh RUN rebuilds the state needed for the new run, preventing stale variable references. - When RUN or CONT returns to Ready, Windows and UEFI discard queued gameplay keys and custom repeat state. KEYDOWN remains non-consuming during a program, but old movement/fire keys no longer reach the editor, INKEY$, INPUT$ or LIST afterward. - UEFI can reuse parallel workers for a running program, reducing the cost of repeated PARFOR loops. Supported AVX2 processors can use the accelerated paths even where firmware did not enable the required processor state. - Startup reports usable SIMD capability and framebuffer access status. Graphics PUT ...,PSET has faster full-frame presentation where supported. - 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 and supported UEFI firmware can share independent iterations among several workers. Repeated loop setup and parallel framebuffer drawing need less overhead. - Eligible horizontal/vertical LINE operations, boxes and filled boxes run faster. PRINT and LOCATE can coexist with surrounding accelerated work, and native integer FOR/NEXT behavior is corrected. - 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. - JIT OFF uses the complete classic interpreter, providing a direct interpreter-versus-JIT comparison. - 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 are recognized 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 makes array memory reusable without moving other live arrays; retained VARPTR addresses of those live arrays remain stable. - Replacing a LOADBMP slot releases its previous bitmap memory. Failed loads do not retain temporary allocations. FRE(0) includes reusable memory. - 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 and clockwise display rotation through ROTATE. - 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 sets the default text rectangle or creates named @n windows using row1,column1,row2,column2, with 1-based inclusive screen text coordinates. PRINT @n, CLS @n and LOCATE @n can address the named 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 reusable memory. 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 uses row,column text-cell positioning and provides keyboard/mouse selection, columns, display truncation, optional colors, titled single/double frames and optional separators. Single-click or Enter accepts; Escape/right-click returns -1. Optional key and click-coordinate outputs let a BASIC program implement menus. 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. 43. BOUNDED FIELD INPUT ACCEPT supplies a single-row field with filtering, default values, horizontal scrolling, selection, clipboard editing and undo. Optional key/click outputs support forms; RESTART resumes the last yielded field. 44. STATEMENT-LEVEL CONTINUATION CONT NEXT executes one statement from a saved pause, preserving inline-IF context. Resumable stops retain sprite instances for CONT. 45. AUTOMATIC LOOP SIMD Eligible ordinary FOR calculations can run in two-lane SSE2 or four-lane AVX2 packets, including supported counted and hypercomplex recurrences. This is independent of PARFOR's multicore scheduling and requires no new BASIC syntax. Unsupported shapes retain scalar execution. 46. RUNTIME EXPRESSIONS AND INDIRECT VARIABLES EVAL evaluates an expression stored in a string. GETVAR, SETVAR and DCLVAL read, assign and declare ordinary variables and arrays by name. 47. FILE ATTRIBUTES AND DRIVE QUERIES FILEATTR reads legacy file/directory attributes. Windows GETDRIVES, DRIVETYPE and DRIVEPATH$ expose drive-letter roots, types and mappings. GETFILES can skip and count names outside the BASIC filename character set. 48. UEFI DISPLAY ROTATION ROTATE in THOREAU.CFG selects 0, 90, 180 or 270 clockwise degrees for the logical BASIC display, including menus, sprites and the mouse pointer. 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.4.1 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 an explicit declaration before access: DIM, REDIM or DCLVAL can declare an array. GETFILES and Windows GETDRIVES explicitly create/replace their destination arrays. Ordinary array access and indirect assignment never create or enlarge an array automatically. 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. In 3.3, eligible full-resolution one-pixel calculations can use loop SIMD even though the source uses scalar BASIC variables; larger adaptive blocks remain scalar. There is no separate SIMD key or native-complex mode toggle. The 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. Version 3.3 optimizes its scalar JIT execution without changing that BASIC source or enabling FMA; it does not claim to vectorize the entire ray/shading subroutine graph. 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. IDENTIFIER SPELLING AND LENGTH ------------------------------ An identifier begins with an ASCII letter or underscore. Following characters may be ASCII letters, digits or underscores, followed by one normal type suffix: %, &, &&, !, #, $ or @. Names remain case-insensitive. An underscore does not create local scope, privacy or special access. An unsuffixed name beginning with underscore defaults to DOUBLE. DEFINT, DEFLNG, DEFI64, DEFSNG, DEFDBL and DEFSTR letter ranges apply only to A-Z; use an explicit suffix to choose another type for an underscore name. DEFxxx _ is not a declaration form. The base-name limit is 37 characters, excluding the optional suffix. Longer names raise Identifier too long instead of being silently truncated. A name used with DEF FN counts its FN prefix toward the same limit, including when the spaced DEF FN spelling is used. FIND/REPLACE WORD, XREF, AUDIT, RENUM, DRAW variable substitution and selected- state schemas recognize underscores. Arbitrary Unicode identifiers are not supported. RUNTIME EXPRESSIONS AND INDIRECT ACCESS -------------------------------------- EVAL evaluates one expression held in a string. GETVAR and SETVAR read and assign a variable or array element whose name is chosen at runtime. DCLVAL declares a scalar or array by name. Their full syntax and restrictions are in VARIABLES / DATA / CONVERSION below. DIM and REDIM already accept runtime bound expressions. DCLVAL additionally lets the program choose the name. Arrays retain explicit dimensions and bounds checks; indirect assignment does not create or grow them. EVAL does not execute statements, and no EXEC command or DIM A(AUTO) form is provided. 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. ON BREAK GOTO 0 removes only the custom break target: Escape again uses normal interruption. It does not turn off break detection or ON ERROR. A nonzero break target prevents PARFOR; removing that target does not waive PARFOR's other safety restrictions. With JIT ON, errors in later source lines are reported when those lines are reached rather than at an earlier valid statement. Undefined GOTO/GOSUB targets are reported at the jump; malformed text at an existing target is reported at that target. LOCATE rejects invalid separators and trailing text consistently in direct and program execution, including named text windows. ON ERROR and RESUME NEXT remain available for these ordinary BASIC errors. 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 DISPLAY ROTATION ===================== This startup setting applies only to the x64 UEFI build. Add a line to THOREAU.CFG in the directory containing the EFI executable: ROTATE = 90 Keep any existing KEYB line. ROTATE may appear before or after it. Standalone applications made with CREATEEFI 3.4 read the same adjacent configuration; re-create older EFI applications to include this support. Value Clockwise rotation ----- ------------------ 0 None; default when the setting or file is absent 90 One quarter turn clockwise 180 Half a turn 270 One quarter turn counterclockwise The keyword is case-insensitive. Spaces or tabs around '=' are optional, and ROTATE 90 without '=' is also accepted. A trailing ';' or '#' starts a comment. Use ASCII or UTF-8 text, not UTF-16. An initial UTF-8 byte-order mark is allowed. The last ROTATE directive wins. Invalid directives warn and disable rotation. Files longer than 2,047 bytes also disable rotation with a warning; keep the configuration small. ROTATE is not a BASIC statement. HELP ROTATE describes the setting. Restart the EFI after changing the file; runtime KEYB changes do not affect rotation. LOGICAL SCREEN COORDINATES At 90 or 270 degrees, logical screen width and height exchange places. For example, a native 1080 x 1920 mode becomes a 1920 x 1080 BASIC screen. SCREEN MODES and VIDEOMODE report these logical dimensions. SCREEN width,height matches them, while SCREEN MODE n keeps the existing native mode index n. Rotation remains active after a mode change; it does not add physical modes. Text, graphics, menus, sprites, editor cursors, the mouse pointer and the F12 monitor use the logical screen. GET/PUT, POINT and saved graphics retain their normal BASIC orientation. GRAMAXX and GRAMAXY report the highest logical pixel coordinates. GRAPITCH reports the logical row stride in pixels. SCRNADR refers to the logical screen, not the panel's native memory layout. Use the reported pitch and dimensions, and obtain addresses again after changing video mode. POINTER INPUT MOUSEPOS, mouse state and click outputs remain logical BASIC-screen pixels. Relative mouse movement keeps its normal right/down axes. Absolute firmware coordinates are converted from panel-native orientation to the logical screen. A device whose firmware already rotates its absolute coordinates may require device-specific handling. Check touch orientation on the actual hardware; no device-specific touch calibration is guaranteed. MEMORY, DIAGNOSTICS AND LIMITS Nonzero rotation needs extra display memory, approximately 12 bytes per visible pixel, plus a small allocation overhead. A 1920 x 1080 display uses about 23.7 MiB for this, in addition to BASIC and other runtime memory. ECONOMY shows the allocated display memory. Rotation also adds display-processing work; it does not promise a particular frame rate or vertical synchronization. If the initial rotated display cannot be established, Thoreau warns and uses native orientation where possible. A display which requires a RAM buffer may still fail when that memory is unavailable. A later mode change that cannot allocate its required display memory leaves the current mode intact. Startup and SYSTEMINFO$(10) report rotation and logical/native dimensions. Firmware setup screens, early firmware text, unrelated EFI programs and the Windows desktop are not rotated. ROTATE=0 retains normal display behavior. 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) WINDOWS SHORTCUT CHARACTERS Alt+printable keys and previously silent Ctrl+digit/punctuation combinations return the ordinary character byte selected by the active layout, Shift and Caps Lock. Ctrl+A through Ctrl+Z retain codes 1..26, and supported function or navigation combinations retain their existing two-byte encoding. No new CHR$(1) prefix or modifier-specific printable-key encoding is introduced. Shift, Ctrl and Alt pressed alone do not add a character event. Repeated application Alt shortcuts no longer cause the unwanted Windows menu beep. Character events are not duplicated, including Ctrl+H, Ctrl+I and Ctrl+M. Alt+Space remains the Windows system menu. Alt+F4, Alt+Tab, Alt+Escape, Windows-key combinations and Alt+numpad entry stay with Windows. AltGr text entry is preserved. F11/Alt+Enter remain fullscreen controls and F12 remains the debugger; these reserved keys are not ordinary INKEY$ events. Custom KEYREPEAT timing applies to the new shortcuts. Releasing the key or leaving the application stops its repeat. Characters still need to be representable in the BASIC character set. Older Windows versions before Windows 10 version 1607 have not been verified for this shortcut handling. KEYDOWN reports the key's current held state, not the modifiers attached to a previously returned INKEY$ event. A released modifier will no longer be down. ACCEPT form mode supplies a distinct Shift+Tab result for field navigation; this does not change the global INKEY$ Shift+Tab encoding. UEFI keeps its raw USB HID translation and firmware fallback. Firmware-only input can return only keys and modifiers that the firmware supplies. 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 logical BASIC-screen pixels on both platforms, independently of WINDOW graphics coordinates. With UEFI rotation, absolute input follows the logical screen and relative movement retains its normal axes: 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. When ROTATE is 90 or 270, their reported logical width and height are exchanged. SCREEN width,height finds an exact matching logical resolution; SCREEN MODE selects the same indexed GOP mode. The orientation stays active across mode changes. 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][,XOR] 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. A final XOR modifier applies to a line, B outline or BF fill. It may follow the color directly when no box mode is needed; an empty box field is also accepted. Omitted color still uses the current foreground. The color mask is resolved normally, then XORed into the low 24 bits of the sprite-free surface. Repeating the same geometry/color restores the original pixels. Palette 15 (white) inverts all 24 color bits. STEP and WINDOW/VIEW mapping still apply. Box corners and degenerate geometry are toggled once rather than twice. LINE XOR works in the interpreter and ordinary JIT/FOR paths. It is rejected inside PARFOR because overlapping read/modify/write operations are not safe independent stores. This is separate from the existing graphics PUT XOR mode and the numeric/logical XOR operator. 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. Transparency information is shared by all instances of a loaded image, so additional instances do not need another copy of that information. 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. COMMAND EDITOR AND SINGLE-STEP EXECUTION ======================================== Direct command entry and EDIT treat text wrapped across display rows as one logical line. The input buffer survives scrolling and narrow text windows. Home/End move within that logical line and Enter submits the whole line, regardless of which wrapped display row contains the cursor. EDIT restores stored source directly, including parts no longer visible on the screen. The capacity limits are unchanged: 255 typed bytes, including a program line number and separator, and at most 244 bytes of stored program body. Display wrapping does not join separate physical lines in a source file. Repainting only updates text and its deleted tail; an empty Ready row does not erase unrelated graphics beneath or after it. LIST NOWAIT disables paging but remains interruptible with Escape between source lines. The normal pager also recognizes Escape arriving during its key poll. A cancelled listing leaves a paused continuation and its sprites intact. Captured output is non-interactive. CONT resumes a saved STOP, breakpoint or untrapped break. CONT NEXT executes one statement and pauses before the next statement, including inside an inline IF branch. GOSUB steps into its target. Timer/mouse callbacks are deferred for the step. Ordinary compiled regions cannot run ahead, and the configured JIT ON/OFF setting and caches are not changed. PARFOR is one atomic statement for stepping, subject to its normal restrictions. The selected inline-IF branch is saved independently of commands typed at the prompt. A resumable pause hides sprite overlays without destroying instances; CONT restores their presentation. END, an unhandled error or program changes that invalidate continuation still perform normal cleanup. CONT without a valid saved continuation reports Can't continue. NATIVE EXECUTION ================ JIT ON is the default. JIT OFF selects the complete classic interpreter. Supported calculations run as native x64 code without changing stored BASIC programs. Unsupported paths automatically use ordinary interpreter execution. FOR retains its observable sequential behavior. PARFOR is the explicit choice for independent multicore work; see its reference for scalar and array rules. AUTOMATIC LOOP SIMD Eligible independent FOR calculations can process four iterations together with usable AVX2, or two with SSE2. The outer FOR variable must be DOUBLE, with an exactly representable integral current value and positive integral STEP. Fractional limits are allowed when they select the same iterations. Short tails, dependencies between iterations and unsupported operations keep ordinary scalar execution. Supported calculation sections can contain up to eight inner FOR/NEXT loops with DOUBLE counters. Eligible inner limits and steps may differ between iterations and can be positive, negative or fractional. Integer-typed inner counters and unsupported exits do not qualify. Plain counted numeric loops use the scalar path on SSE2 by default; eligible hypercomplex loops can use two-iteration SSE2 execution. Complex, quaternion and octonion calculations support eligible constructors, matching-dimension arithmetic, real scaling, conjugation, component reads and norms. This does not provide unrestricted acceleration of transcendental functions or arbitrary array lookups. Calculations preserve their individual branches, escape times and arithmetic order. Array access and drawing remain in their original per-iteration order. Unsupported or exceptional cases use the ordinary scalar path with normal error handling. OTHER OPTIMIZATIONS AND LIMITS Eligible scalar comparisons, DOUBLE arithmetic, square roots and exact repeated expressions need less repeated work. Eligible DOUBLE bases raised to exact positive variable-integer exponents from 1 through 65536 have an accelerated path. Zero bases, other exponent types and exceptional cases retain normal behavior. Literal integer powers keep their existing optimization. These optimizations do not introduce reduced precision or change arithmetic order. Tracing, profiling, stepping and event/error-handler contexts can limit which optimizations apply. SYSTEMINFO$(6) and startup report usable processor capabilities, not a guarantee that every loop uses them. Performance depends on the program, processor, worker count and display environment. 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. String literals may end at the physical source-line terminator without a closing quote. Colons, apostrophes and REM inside the still-open literal are text, not statements or comments. This does not repair missing parentheses or continue the literal onto another source-file line. Visual screen wrapping of one editor line does not create a new source-line terminator. ACCEPT options are separated from the destination by comma or semicolon; the earlier colon spelling remains accepted. Only a colon in that delimiter position belongs to ACCEPT. A colon after its destination and optional outputs is an ordinary statement separator. IF may have an empty THEN or ELSE branch. In IF condition THEN ELSE target, a true condition does nothing and a false condition follows the ELSE target. The condition is still evaluated. AUDIT accepts these branches while checking the condition and any nonempty branch; IF ... GOTO still requires a target. 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 [NEXT] Does: resume a saved STOP, breakpoint or untrapped break. NEXT executes one statement and pauses before the next, including inside inline IF. GOSUB steps into its subroutine; PARFOR is one atomic statement. Timer/mouse callbacks are deferred during the step. JIT settings stay unchanged, and resumable sprite state is restored. No valid continuation reports Can't continue. Example: CONT DELETE Syntax: DELETE range Does: remove stored program lines Example: DELETE 1000-1990 EDIT Syntax: EDIT line | EDIT . | EDIT ERL Does: edit a stored/current line or the last error line. Direct entry and EDIT retain the complete logical line across wrapped rows and scrolling. Home/End use the logical line. Limits remain 255 typed bytes and 244 stored body bytes; EDIT primes from stored source. 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: run a side-effect-free syntax phase, then static structural checks. The syntax phase checks core expressions, assignments, control flow, ACCEPT, unknown statements and delimiters, including unreachable branches. Empty THEN/ELSE branches are accepted, not reported as missing statements. It does not evaluate expressions or execute code, call DEF FN bodies or create program variables. Specialized grammars with only name/delimiter checking are reported explicitly. A clean audit is not proof that all arguments, runtime types or execution paths are valid. Structural checks cover undefined literal targets, FOR/PARFOR/NEXT and WHILE/WEND order, FN calls lacking definitions, and function-name conflicts. OPEN ... FOR, CONT NEXT and RESUME NEXT are not mistaken for loop openings/closures. Computed targets are not guessed. Scalar/function-name warnings concern assignment targets, not names read in expressions. Comparisons with INKEY$, CLIPBOARD$, DATE$, TIME$, ERROR$ and other built-ins do not create scalar-name warnings. Actual conflicting assignments still warn, including LET, FOR/PARFOR counters and assignments inside THEN/ELSE branches. The PARFOR scalar phase warns when a numeric/@ scalar is both written in a directly visible structured body and possibly read before a definite assignment in that outer iteration. This detects S=S+I without confusing a locally initialized inner recurrence with a global sum. Each warning gives the first such read's source line and 1-based body column, the scalar name and enclosing PARFOR line. One warning is issued per affected scalar per analysed PARFOR. Full scalar assignments establish initialization. IF/ELSE merges retain only assignments made on both paths. Inner FOR/WHILE bodies may be skipped, so their body-only assignments are not guaranteed afterward. Component writes do not initialize a complete @ value. Numeric type suffixes and source-order DEFxxx aliases are respected; live type defaults are not changed. Read-only inputs and the outer PARFOR counter do not receive this warning. This is an advisory check of the visible program text, not proof that every possible execution path has been checked. GOSUB/DEF FN calls, arbitrary jumps, FOR END/WHILE END, unrecognized effects, ambiguous typing, unstructured loop closure and analysis capacity limits skip a body or stop the pass. The summary reports checked/skipped loops and says when remaining source was not analysed. Large or deeply nested bodies may exceed the analysis limits. Earlier syntax/structural checks remain independent when this phase cannot analyse a body. A warning can be intentional when using worker-local state. Its absence is NOT a promise of scalar copy-back: a scalar assigned without first being read is still private. The check does not inspect uses after the loop or identify every possible lost scalar result. It never executes a program statement or creates a reduction. Variables, errors, type defaults and saved continuation are unchanged. May run inside a program and under CAPTURE; warning text is captured through the normal interface. Example: AUDIT END Syntax: END Does: end the program, discard continuation/sprite instances and close files. END has no arguments: trailing tokens, including END FOR, are a Syntax Error. The same boundary rule is used by AUDIT and the native compiler. Colons, inline ELSE boundaries and apostrophe comments are allowed. Use FOR END or WHILE END to exit a loop. 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 include n, n-m, -m and n-; . refers to the current edit line. Paging is standard. NOWAIT disables paging but still polls Escape between lines. Escape also cancels the pager without destroying a saved CONT/sprite state. Captured listings are non-interactive. 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, repeated RUN restarts do not exhaust stack space. 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; CONT NEXT steps one statement. Sprite instances survive a resumable pause, with their overlays hidden until continuation. 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 reachable loop/GOSUB graph is checked for supported operations and permitted shared writes before workers start. These checks do not prove that replacing an ordinary FOR preserves its sequential result or intended algorithm. NUMERIC AND @ SCALARS ARE WORKER-PRIVATE. Each worker starts with its own copy of the pre-loop scalar values (zero for previously absent variables). Those copies belong to the worker, not to each individual iteration: a worker may retain a value between iterations assigned to it. Initialize per-iteration scratch inside the outer PARFOR body whenever its calculation needs a fresh value. PRIVATE SCALAR RESULTS ARE NOT COPIED BACK. Assigning a scalar in PARFOR leaves that scalar's main-program value unchanged. Only the outer induction variable has a defined post-loop counter value on successful completion. This is true even when only one worker runs. PARFOR provides no automatic sum, product, minimum or other reduction. Use ordinary FOR for a sequential total, or write independent contributions into disjoint array elements and combine them afterward. Setting a scalar before the loop supplies its initial worker values; it does not enable final-value copy-back. Numeric/@ arrays are shared. Stores are accepted only under the compiler's disjoint-element/slice rules, normally because one subscript is exactly the PARFOR variable. The programmer must still avoid dependencies on values another iteration may change. Drawing and accepted shared-array stores are explicit output mechanisms; worker-local final scalar values are not. AUDIT warns about some likely scalar accumulators/carried values. It does not change these execution rules, infer a reduction or prove that an unreported loop is independent. See AUDIT for coverage. Absolute PSET and supported LINE forms require an explicit colour and should target disjoint pixels/regions. LINE XOR is rejected because it reads and modifies existing pixels. Shared text cursor/output, WINDOW/VIEW transforms, TRON/TRACE watches, debugger breakpoints, nested PARFOR, an active interpreter IF context and paths requiring classic interpreter fallback are rejected. A nonzero ON BREAK target is also rejected; ON BREAK GOTO 0 removes only that restriction. Timer/mouse-handler restrictions depend on the handler-aware build support; callbacks are not independently dispatched by workers. 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 supported UEFI firmware reuse workers across repeated PARFOR calls during a RUN. Eligible inner calculations can additionally use automatic SIMD packets. That optimization does not relax PARFOR safety rules. 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. THEN and ELSE may be empty. IF condition THEN ELSE target branches only when the condition is false. AUDIT accepts this syntax too. The abbreviated IF condition GOTO form still requires a literal target. 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. ON ERROR GOTO 0 disables only the error handler. ON BREAK GOTO 0 disables only the custom break target, restoring normal Escape interruption and removing that PARFOR restriction. It does not disable Escape or modify ON ERROR. 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. With JIT ON, eligible loops may use automatic SSE2/AVX2 packets. Unsupported paths remain scalar/interpreted; no SIMD BASIC syntax is required. See NATIVE EXECUTION for supported calculations and limits. Profiling, tracing and stepping can limit acceleration. 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 ----------------------------- EVAL Syntax: EVAL(expr$) Does: evaluate exactly one expression from a runtime string. Current scalar variables, dimensioned arrays, ordinary TB functions and DEF FN are available. Numeric, string and hypercomplex result types are preserved; normal assignment conversion applies to a destination. Nothing is added to, MERGEd into, or removed from the stored program. An omitted final quote in a string literal follows the same convention as an ordinary BASIC source expression. Maximum input is 4,095 bytes and 127 expression tokens, with at most 16 nested EVAL calls. Existing expression/DEF FN nesting limits also apply. Empty input, NUL/CR/LF bytes, comments outside quoted text, trailing statements or commas, and invalid expression syntax raise errors. Syntax is checked before evaluation; runtime type, bounds and function-argument errors can still occur during evaluation. Runtime errors are reported through the caller's ERR/ERL/ERROR$ and ON ERROR handling. A dynamic expression has no new numbered line. EVAL works with JIT ON; the setting remains enabled for the rest of the program. EVAL is not eligible inside PARFOR, including through a called DEF FN. It is not a sandbox: supported functions can read input/files/network state or otherwise have observable effects. Do not evaluate untrusted text on the assumption that restricting it to an expression makes it harmless. There is no EXEC statement. GETVAR Syntax: GETVAR(name$[,index1[,index2[,index3[,index4]]]]) Does: read an ordinary scalar or an existing array element by a full identifier held in a string. The name is not an expression: spaces, parentheses, component suffixes such as .I, and statement text are not accepted inside it. Use normal type suffixes and case-insensitive identifiers; DEFxxx/default-type alias rules still apply. With no indices, an absent scalar returns its typed zero/empty value without declaring it. With indices, the array must exist, its rank must match the supplied count and every subscript must be in range. Indices use the same integer conversion as ordinary array subscripts. The result retains its numeric/string/@ type. Hypercomplex component access may be applied to the resulting expression outside the name. Runtime/pseudo-variable names such as ERR, TIMER or GRAMAXX are excluded; use their ordinary expressions instead. GETVAR works with JIT ON but is not available inside PARFOR. SETVAR Syntax: SETVAR value,name$[,index1[,index2[,index3[,index4]]]] Does: assign an ordinary scalar or existing array element indirectly. value and name$ are expressions; the resulting name follows GETVAR's complete-identifier rules. Normal numeric narrowing, overflow, string and hypercomplex assignment rules apply. An absent scalar is created after successful value conversion. An array is never implicitly created or grown. Runtime names cannot be assigned. SETVAR is a statement; it does not execute text from name$. The command is available with JIT ON but not inside PARFOR. DCLVAL Syntax: DCLVAL name$[,bound1[,bound2[,bound3[,bound4]]]] Does: declare by name. With no bounds, create an absent scalar initialized to typed zero/empty. With one to four bounds, dimension an absent array as DIM would, with OPTION BASE and runtime upper-bound values. Ordinary suffix/default typing is used. Existing scalars/arrays of the same identity raise Duplicate definition; a scalar and array can have the same base name as in ordinary BASIC. Function names cannot be used for arrays. A failed declaration does not create a partial array or replace an existing one. DCLVAL is a statement, not a function, and is unavailable inside PARFOR. 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; empty when no event is waiting. Supported extended keys return CHR$(0)+CHR$(DOS scan). Windows Alt+printable and otherwise silent Ctrl+digit/punctuation shortcuts return their ordinary character byte; Ctrl+A..Z retain codes 1..26. Modifier keys alone stay silent. See INKEY$ EXTENDED KEYS for reserved shortcuts and platform limits. 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$. This is live state, not a modifier snapshot for a previous key event. 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 screen PRINT CHR$(7): a built-in 800 Hz, 200 ms tone with short attack/release ramps, independent of the GM bank and instrument channels. Repeated BEL extends the tone. Windows uses PCM with an OS Beep fallback; UEFI requires a supported available HDA output path. PRINT# writes bytes, not console sound. 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$ ACCEPT Syntax: ACCEPT variable[,key$[,clickX,clickY]] ACCEPT [AT(row,column)] [SIZE(n)] [VALIDATE(set$|DIGIT|NUMERIC|UALPHA|ALPHA[,...])] [BEEP] [DEFAULT] [UCASE|LCASE] [RESTART] , variable[,key$[,clickX,clickY]] Does: edit one string or numeric scalar/array element in a single-row field. The displayed line breaks are explanatory, not continuation syntax. Options may be reordered, but not repeated; UCASE/LCASE conflict. A comma or semicolon separates options from the destination. The earlier colon spelling remains accepted as an internal delimiter. With no options, write ACCEPT followed directly by the destination. Option words are contextual, not new globally reserved keywords. AT uses LOCATE-style 1-based row,column coordinates. Within a default TXTWINDOW, the position is relative to its origin; VIEW PRINT still restricts valid physical rows. Without AT, input starts at the current cursor. SIZE accepts 1..255 input bytes; the default limit is the remaining row width, capped at 255. A long field scrolls horizontally instead of wrapping. No question-mark prompt is added. DEFAULT preloads the existing destination through the case and validation filters. UCASE/LCASE converts ASCII case before filtering. VALIDATE may combine string sets/ranges and these named sets: DIGIT 0-9 NUMERIC 0-9 plus . e E d D + - UALPHA A-Z ALPHA A-Z and a-z These are character filters, not complete numeric-format validators. An empty permitted set is an error. Without VALIDATE, printable BASIC bytes are accepted. BEEP sounds on a fresh entry, not on a matching RESTART. Strings retain the platform's existing BASIC byte encoding. Left/Right/Home/End move the caret; Shift with those keys selects. Insert toggles insert/overwrite; Backspace/Delete remove text. Ctrl+A selects all; Ctrl+C/X/V copy/cut/paste; Ctrl+Z swaps the latest edit snapshot for one-level undo/redo. Ctrl+Insert, Shift+Delete and Shift+Insert are clipboard alternatives. Pasted control bytes never submit the field or execute code. Rejected input cannot erase a selection. F12 opens the protected debugger, rather than returning an application function-key event. NORMAL INPUT (key$ omitted) Enter converts and commits. Malformed numeric text beeps and remains editable; overflow is a normal BASIC error. Escape leaves the target unchanged and follows ON BREAK, including the existing CONT behavior for an untrapped break. Enter advances to a new line unless AT was supplied. Function/navigation keys not used for editing stay internal. FORM INPUT (key$ supplied) key$ must be a string scalar. Optional clickX,clickY must both be numeric scalars that can hold -1 and the logical framebuffer bounds. Destination and output variables must not alias each other. These outputs enable returns to the BASIC form controller: CHR$(13) Enter CHR$(9) Tab CHR$(0)+CHR$(15) Shift+Tab CHR$(0)+CHR$(scan) Up/Down, Page Up/Down, delivered function keys "MOUSE" Left click outside the field CHR$(27) Escape or right-click cancellation other control byte Unclaimed control shortcut (for example Ctrl+S) printable byte Alt+character or Ctrl+printable fallback, when the backend exposes its modifier state Editing keys and clipboard shortcuts listed above do not exit. Ctrl+Alt/AltGr printable input remains text, not a form shortcut. Physical F11 on Windows remains fullscreen; F12 remains the debugger. Shift+Tab is distinguished using the captured event modifier. Other KEYDOWN queries remain live held-key state and can change after key-up. Firmware-only UEFI input is limited to the events/modifiers supplied by the firmware; no missing modifier information is fabricated. Non-cancel exits convert and commit the field before returning. Malformed numeric input cannot leave through Tab, a function key or an outside left click: it beeps and stays editable. Escape/right-click still cancels it. Overflow is a normal BASIC error, not a successful form exit. Escape/right-click leaves the destination unchanged and returns normally without invoking ON BREAK. No form exit forces a newline, even without AT; the BASIC caller controls layout/focus. A left click inside the field moves its caret and clears selection; it does not exit. Outside left clicks return their queued clickX,Y in logical framebuffer pixels (x,y order, not row,column text cells). Keyboard and cancellation returns set both coordinates to -1. Mouse events are consumed; the existing pointer visibility setting is not changed. This is caret positioning, not a mouse-drag selection API. An error leaves the destination and output values unmodified. RESTART RESTART requires key$ output. On a matching re-entry, it restores the last yielded field's draft, caret, selection, horizontal view, insert/overwrite setting and one-level undo/redo state. This lets a controller ignore an unhandled F3 by returning to the same ACCEPT. With no AT, the original field origin is restored too. Matching requires the same source line/statement position, destination scalar or array element, resolved type, options other than RESTART, limits, filter, case conversion and compatible physical field geometry. Program changes or resets can invalidate saved state. First use or any mismatch initializes the field normally, applying DEFAULT when specified. RESTART can therefore be present on every execution of a form's ACCEPT statement. Only the LAST yielded field is retained, not every field in a form. Enter completes it and clears restart state. Another opened ACCEPT replaces it; RUN/NEW/CLEAR clear it through the normal runtime reset. A matching RESTART deliberately uses the saved draft, not a value subsequently assigned by the BASIC controller. To show a newly supplied value instead, start fresh without RESTART and use DEFAULT. Restart state is session-local editor data, not a STATEWRITE checkpoint. 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 [row][,column][,legacy-extra...] LOCATE @n,row,column Does: move the text cursor using 1-based coordinates. Omitted row/column values stay unchanged. Legacy comma-separated extra fields in the ordinary form are accepted and ignored. With no default TXTWINDOW, row is an absolute whole-screen row. VIEW PRINT restricts valid physical rows rather than changing the coordinate origin. Within a default TXTWINDOW, row and column are relative to its origin. The named @n form requires both coordinates and positions that window's own cursor within its bounds. Semicolons and invalid trailing text are Syntax errors in direct mode and stored programs, with JIT on or off. A following colon or valid ELSE boundary still ends the statement normally. Invalid arguments do not apply a partial cursor movement, although printing an error message may itself move the visible cursor. Errors follow normal ON ERROR, ERR/ERL and RESUME NEXT handling. 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 row1,column1,row2,column2 TXTWINDOW @n,row1,column1,row2,column2 TXTWINDOW Does: define a text rectangle using row,column pairs, as LOCATE does. Both corners are 1-based, inclusive positions on the whole-screen text grid, not pixels or positions relative to an existing window. row1,column1 is the top-left corner; row2,column2 is the bottom-right. Rows must fit TXTMAXY, columns must fit TXTMAXX, and neither ending coordinate may precede its starting coordinate. The ordinary form sets the default region for text output. LOCATE and ACCEPT AT then use positions relative to that region's origin. The @n form defines or replaces named window n (0..7), addressed by PRINT @n, CLS @n, COLOR @n and LOCATE @n. Named windows keep their own cursors and do not replace the default region. Bare TXTWINDOW removes the default region and homes the ordinary cursor. Any active VIEW PRINT restriction remains in effect; named windows are not deleted. The row-first change introduced in the updated 3.4 build is retained in 3.4.1. Swap each pair only in older column-first calls, including the @n form; keep the window number in place. Do not swap calls already using row,column. There is no automatic old-order detection. Graphics coordinates remain x,y; this change applies to text cells. Example: TXTWINDOW 20,1,30,80 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[,skipped]]] Does: create/replace a one-dimensional string array; no DIM is needed. count and optional skipped are distinct numeric scalar outputs. Default filespec is * in the current directory; the specification may include a directory path. There is 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. Hidden/system entries are included; use FILEATTR to inspect them. File masks are tested case-sensitively against native UTF-16 names BEFORE conversion to BASIC bytes. * matches any sequence, ? matches one UTF-16 code unit, and *.* also includes extensionless names. A supplementary Unicode character occupies two code units. Included directories bypass the file mask, just as before. With skipped omitted, an otherwise eligible name that cannot be represented raises Filename cannot be represented in BASIC. With skipped supplied, such entries are omitted and skipped receives their count. A nonmatching file is not an omission and is not counted. Supply filespec and flags explicitly to reach the skipped argument. Only representability failures are tolerated; access/disk errors, malformed directory data, overlong names, allocation failures and interruption do not publish a partial successful result. No '?' or other lossy alias is returned. Windows filenames still use CP437; UEFI filenames still use ASCII. Unrepresentable entries cannot be opened merely by enabling the skipped-count option. OPTION BASE applies. Empty results set count=0 and leave one empty array element; always iterate by count. A failed statement preserves the previous array and output values. A successful statement sets skipped=0 when nothing was omitted. Replacing an array invalidates retained element addresses. There is no GETDIRS command. Example: GETFILES ENTRIES$(),N,"CHAPTERS\*.txt",7 Example: GETFILES FILES$(),N,"*.BAS",1 FILEATTR Syntax: FILEATTR(path$) Does: read the legacy attribute mask of a file or directory, on Windows or UEFI. Combine the following bits with AND: 1 read-only 2 hidden 4 system 16 directory 32 archive A successful query with none of these bits returns 0 (normal). Additional native attributes and filesystem details are not exposed. -1 means the query is unavailable/failed; check -1 BEFORE masking bits. Malformed paths, wrong argument types and path-allocation errors can still raise normal BASIC errors. Wildcards are rejected. GETFILES entries are relative to the listed directory: prepend that directory when it differs from BASIC's current working directory. Attributes are a snapshot, not an access or filesystem-safety promise. GETDRIVES Syntax: GETDRIVES roots$(),count Does: Windows only: create/replace a one-dimensional string array of mapped drive-letter roots, sorted A-Z, each in the form C:\. OPTION BASE and empty-result/error rules match GETFILES. No DIM is required. The list reflects the caller's Windows drive mappings; it does not enumerate letterless volumes or physical disks, and a returned drive is not necessarily ready or accessible. On UEFI this statement raises GETDRIVES is Windows-only. DRIVETYPE Syntax: DRIVETYPE(root$) Does: Windows only: report the drive classification: 0 unknown 1 no root/absent 2 removable 3 fixed 4 network 5 optical 6 RAM disk Accepts a single ASCII drive letter, a letter with colon, or a drive root ending in backslash/forward slash. Letters are case-insensitive. It is not a physical-bus/USB detector or media-readiness test. Other path forms raise Expected drive letter or root. UEFI reports DRIVETYPE is Windows-only. DRIVEPATH$ Syntax: DRIVEPATH$(root$) Does: Windows only: return the mapped network resource name, normally a UNC share path. Accepts the same drive-letter/root forms as DRIVETYPE. A local drive or an unavailable/not-connected network mapping returns an empty string; unexpected provider errors raise Network drive query failed. This does not initiate a connection. Network resource text must be representable in CP437 and fit the 4,095-byte path limit. Otherwise it raises an error rather than returning a lossy name. UEFI reports DRIVEPATH$ is Windows-only. FLUSH Syntax: FLUSH [#n[,#m...]] Does: drain BASIC output buffers and ask the platform to commit file data to storage. 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 row,column,width,height,maxEntry,columns,items$(),count,choice [,fg,bg[,selectedFg,selectedBg]][,frame] [,title$[,key$[,clickX,clickY]]] [SEPARATORS] Does: draw a modal selector at 1-based row,column on the physical text grid. This is a breaking coordinate-order change: swap the first two arguments of older SELECTBOX calls. There is no old-order alias. width,height remain in that order, include the frame, must be at least 3 by 3 and 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 clipped to the column width without changing the strings. items$() is a one-dimensional string array. count is the number of entries beginning at OPTION BASE; choice is a numeric scalar holding the initial/returned actual array index. An invalid initial index starts at the first entry. Escape/right-click returns -1. Colors use COLOR conventions: provide the normal pair or both normal and selected pairs. Defaults use the current colors and reversed selection. The optional numeric frame can stand alone or follow color pairs: 1=single (default), 2=double. Real CP437 frame codes are: single: 218,191,192,217,196,179 double: 201,187,200,188,205,186 The optional title string follows any numeric options and is clipped to the top frame. An empty title permits outputs without a label. CP437 CHR$(24) and CHR$(25) indicate entries above and below the view, in both frame styles. Arrows move, Home/End select first/last, and PgUp/PgDn move by page. In ordinary modal mode, an entry's first character finds the next match. Enter or a single left-click accepts; a double-click is also accepted. The wheel navigates. Right-click cancels like Escape. Supplying scalar key$ enables menu mode. Navigation stays modal; other keys return the current choice and INKEY$ bytes. One-column Left/Right returns to the caller instead of staying in the selector. The key output is: CHR$(13) Enter or accepted item click CHR$(27) Escape/right-click, with choice=-1 "MOUSE" Outside left-click, with current choice retained other The pressed key's ordinary/extended INKEY$ bytes empty Empty or all-separator list, with choice=-1 Menu-mode character keys, including delivered Alt/Ctrl shortcuts, return to the caller rather than performing first-letter search. Outside left-click is ignored without key$. Only the Enter/click return means acceptance. clickX and clickY are optional paired numeric scalar outputs after key$. They receive the queued accepted/outside left-click position in framebuffer pixels, not text cells. Keyboard, cancellation and empty-list returns set both to -1. Output types must hold their range. A trailing SEPARATORS keyword has no preceding comma. It makes an item exactly "-" an unselectable horizontal rule. One-column rules join the frame; multi-column rules fill their slot. Navigation and character matching skip rules, and clicking one does nothing. count and returned indices still include separator slots. An initial separator seeks forward, then backward. Empty/all-separator lists return -1, empty key$ and -1,-1 coordinates without opening a box. Without SEPARATORS, every item, including "-", is selectable text. Selector mouse events are consumed. Cursor, colors and key repeat are restored. The drawn box remains; 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][,XOR] LINE INPUT has its own input syntax. Does: draw a line, box or filled box; color may be a palette index, packed 0xRRGGBB or an RGB triple. Final XOR uses the color as a 24-bit mask; repeating the same drawing restores pixels. Normal JIT/FOR supports it; PARFOR rejects LINE XOR. See the main LINE section for details. 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 an exact existing GOP mode by its logical dimensions after ROTATE. SCREEN MODES lists those dimensions without changing native mode indices. 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; with UEFI ROTATE, the logical BASIC screen. Use the reported logical GRAPITCH and dimensions, and obtain the address again after a mode change. 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.4.1) 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; UEFI rotation and logical/native dimensions when active 11 Current JIT ON/OFF setting 12 Build date/time, compiler and debug/release 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 calibrated at startup and displayed to three decimals. It is a counter rate, not a live CPU clock or throughput measure; the query does not recalibrate it. Memory sizes are allocated capacities, not installed RAM or free memory; use FRE for live available memory. CPU information reflects what the machine or virtual machine reports. Build identification does not measure speed. 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. On UEFI, the required battery information must be available through firmware. No reading is inferred when the device or its information 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; also the graphics PUT and LINE exclusive-OR drawing modifier. Drawing twice with the same geometry and color restores pixels. LINE XOR is not accepted in PARFOR. 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 ACCEPT, 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 (including single step), 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 and startup display rotation are configured in THOREAU.CFG beside the EFI. Windows ignores these settings. - 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