From 5ef117727e826d34db794577cec34414e88d8b0a Mon Sep 17 00:00:00 2001 From: Luxferre Date: Sat, 13 Jun 2026 13:06:04 +0300 Subject: [PATCH] returned to the traditional RND() function --- README.md | 4 ++-- lttb-manual.md | 9 ++++++--- lttb.tcl | 17 +++++++++-------- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 66b253e..8e41ce4 100644 --- a/README.md +++ b/README.md @@ -9,11 +9,11 @@ Luxferre's Truly Tiny BASIC (henceforth LTTB) is a lean dialect of the BASIC pro The LTTB specification expands upon the original Design Notes in the following manner: - Line numbers from 1 to 32767 are supported. -- A special pseudo-variable `$` is introduced, which holds a random number from 0 to 9999. - Any invalid statement (including `REM`) can be used for comments. - No command can be abbreviated inside `IF` statements. - `LET` and `THEN` keywords are optional. - `IF` statements also allow inserting line numbers after `THEN`, making it possible to write self-modifying programs. +- A special `RND(n)` function is introduced that generates a random number from 0 to `n-1`. - The `NEW` command is synonym to `CLEAR`. - The `BYE` command can be used to exit the interpreter. - In the environments that support file systems or some kind of external file I/O, the `LOAD` command can be used to load BASIC programs into memory, and the `SAVE` command can be used to save BASIC programs from memory. @@ -41,7 +41,7 @@ Besides, the goal is not just to make one implementation and call it a day, but In general, you should be able to run anything compatible with: * the original [Design Notes](http://www.ittybittycomputers.com/IttyBitty/TinyBasic/DDJ1/Design.html) by Dennis Allison; -* the original Tom Pittman's 6800TB (if the program doesn't have any `USR` or `RND` calls and has proper spacing between the command and the rest of the statement); +* the original Tom Pittman's 6800TB (if the program doesn't have any `USR` calls and has proper spacing between the command and the rest of the statement); * the [Damian Gareth Walker's implementation](http://tinybasic.cyningstan.org.uk/), provided all program lines are properly numbered (because that implementation uses auto–numbering when loading the programs). ### Will there be any TBX (Tiny BASIC Extended) or PATB (Palo Alto Tiny BASIC) compatibility? diff --git a/lttb-manual.md b/lttb-manual.md index 25009b9..6977b87 100644 --- a/lttb-manual.md +++ b/lttb-manual.md @@ -7,12 +7,11 @@ Luxferre's Truly Tiny BASIC (henceforth LTTB) is a lean dialect of the BASIC pro * 16-bit signed integers (from -32768 to 32767) as the only data type * String literals (only allowed in the `PRINT` statements, usually auto-uppercased) * 26 single-letter variables available (`A` to `Z`) -* A special pseudo-variable `$` holding a random number from 0 to 9999 * Line numbering from 1 to 32767 * Unbounded subroutine call stack * Supported commands: `LET`, `IF ... (THEN)`, `INPUT`, `PRINT`, `GOTO`, `GOSUB`, `RETURN`, `END`, `LIST`, `CLEAR` (synonym `NEW`), `RUN`, `LOAD`, `SAVE`, `BYE` * Any invalid command is ignored, so it still is possible to use e.g. `REM` for comments -* Allowed operations within expressions: `+`, `-`, `*`, `/`, parentheses `()` +* Allowed operations within expressions: `+`, `-`, `*`, `/`, parentheses `()`, `RND(n)` function * Allowed relational operators with `IF` statements: `=`, `<>` (synonym `><`), `>`, `>=`, `<`, `<=` ## The interpreter @@ -31,6 +30,10 @@ Similarly to other Tiny BASIC implementations, LTTB does not support a dedicated In case the evaluation result is outside the allowed range, it is automatically converted to this range (by taking it modulo 65536 and then subtracting 32768 if the modulo is over 32767) after every evaluation. +## `RND` function + +The single function supported by LTB to use within expressions, `RND(n)` aka `$(n)`, takes the argument `n` and returns a (pseudo)random number from 0 to `n-1`. When `n` is negative, the behavior is undefined. It's recommended for the implementations to convert it to positive first by adding 32768. + ## Statements A **statement** in LTTB is a standalone execution unit. It usually corresponds to a single program line, with the exception of using it inside an `IF` statement (see below). @@ -51,7 +54,7 @@ The following commands are the core of LTTB. Evaluates the expression `[expr]` and assigns the result to the variable `[var]`. `LET` is the only core command keyword that can be omitted in LTTB, because `[var]=` is enough to detect the assignment statement. -Examples: `let x=10`, `y = $ + 8` +Examples: `let x=10`, `y = RND(10) + 8` ### `IF [expr1] [relop] [expr2] (THEN) [stmt]` diff --git a/lttb.tcl b/lttb.tcl index 4218ded..9bfbffd 100755 --- a/lttb.tcl +++ b/lttb.tcl @@ -75,12 +75,12 @@ proc lttb_eval {lttb_ex} { if {[string is digit $lttb_ex]} {return [lttb_norm $(int($lttb_ex))]} # pass 1: variable and parentheses substitution global vars + regsub -all -nocase -- {RND} $lttb_ex {0$} lttb_ex lassign {{(((} {}} pre_ex prevc foreach c [split $lttb_ex {}] { set outc {} - if {[string is digit $c]} {set outc $c} + if {[string is digit $c] || $c eq {$}} {set outc $c} if {[string is upper $c]} {set outc $vars($c)} - if {$c eq "$"} {set outc [rand 0 10000]} if {$c eq "("} {set outc {(((}} if {$c eq ")"} {set outc {)))}} if {$c eq "*" || $c eq "/"} {set outc [string cat {)} $c {(}]} @@ -102,16 +102,17 @@ proc lttb_eval {lttb_ex} { set v2 [_lpop valstack] set v1 [_lpop valstack] switch -exact -- $op { - "+" { set res $($v1 + $v2) } - "-" { set res $($v1 - $v2) } - "*" { set res $($v1 * $v2) } - "/" { if {$v2 != 0} {set res $(int($v1 / $v2))} } + {$} { set res [rand 0 $(($v2 + 32768) % 32768)] } + {+} { set res $($v1 + $v2) } + {-} { set res $($v1 - $v2) } + {*} { set res $($v1 * $v2) } + {/} { if {$v2 != 0} {set res $(int($v1 / $v2))} } default { error "Unknown operator: $op" } } lappend valstack [lttb_norm $res] } lassign {{} {} {}} valbuf valstack opstack - set precmap {+ 1 - 1 * 2 / 2} + set precmap {+ 1 - 1 * 2 / 2 $ 3} foreach c [split $pre_ex {}] { if {[string is space $c]} {continue} if {[string is digit $c]} { @@ -128,7 +129,7 @@ proc lttb_eval {lttb_ex} { eval_helper valstack opstack } if {[lindex $opstack end] eq "("} {_lpop opstack} - } elseif {$c in {+ - * /}} { + } elseif {$c in {+ - * / $}} { set prec $precmap($c) while {[llength $opstack] > 0} { set top_op [lindex $opstack end]