returned to the traditional RND() function

This commit is contained in:
Luxferre
2026-06-13 13:06:04 +03:00
parent 3898d40f19
commit 5ef117727e
3 changed files with 17 additions and 13 deletions
+2 -2
View File
@@ -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 autonumbering when loading the programs).
### Will there be any TBX (Tiny BASIC Extended) or PATB (Palo Alto Tiny BASIC) compatibility?
+6 -3
View File
@@ -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]`
+9 -8
View File
@@ -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]