The idea of writing a BASIC interpreter seemed overwhelming so I immediately hit search. There are a lot of BASIC interpreters/compilers out there but the one that was an initial perfect fit was Scott Lawrence's version of Mike Field's port of Tiny Basic. It ran on an Arduino (albiet, barely) and it looked easily modifiable (which turned out to be true). I started by just getting it to run on the Teensy 3 instead of an Arduino. Then I made a simple port for it to communicate with my terminal code via a pair of FIFOs. Eventually I started adding commands and a more sophisticated interface.
As of this post it runs the commands documented below. Based on feedback from fellow hackerspace members, I will change the PCHR command to a set of CHR and ASC functions to more closely match early BASIC environments. Beyond this device, I think both the terminal code and the Tiny Basic interpreter could be combined with a new library, perhaps using DMA, on the Teensy to drive NTSC/PAL or VGA displays with commonly available PS2 or even USB keyboards.
Input can come from keyboard or any of the serial interfaces (e.g. USB host IF) to load programs from a host computer using a terminal emulator. Output may be directed to any serial interface as well as the display (e.g. to save programs via a terminal emulator). Tiny Basic communicates to the outside world through a set of virtual (or physical) serial ports. The local keyboard and display appear to it logically as a terminal (and can be interacted with using escape sequences if desired).
Each line must have a numeric line number (e.g. 10, 20, 30…). Commands may be separated by the colon character (‘:’) on a single line. Commands which immediately goto another line (GOTO, RETURN) cannot have subsequent commands on the same line. Each command is stored as an ASCII representation in memory (no tokenization).
There are 26 variables, A-Z. Each variable is a 16-bit signed number (-32768 to 32767). Variables or literal numbers may be used in expressions.
Tiny Basic provides 32 Kbytes of program memory. Variables and the stack live at the high end of program memory and the program starts from location zero. The MEM command returns how many bytes are available for program code. DATA@, PEEK and POKE can access the entire range but not outside of the program memory (e.g. other DL1416SmartTerm memory in the Teensy address space). There is room for 8 nested FOR loops on the stack or more GOSUBs in this version of Tiny Basic.
The EOT key is used as BREAK to stop execution of a Tiny Basic program.
File names follow the 8.3 rule (a maximum of 8 filename characters and 3 file type characters which should be .BAS for Tiny Basic programs). This version of Tiny Basic is limited to 16 levels of directories on the SD card.
- BYE - exits Basic, soft reboot of Tiny Basic
- END - stops execution from the program, also "STOP"
- MEM - displays memory usage statistics
- NEW - clears the current program
- RUN - executes the current program
- LIST [start line number [, end line number]] - list to end with one line number argument or range between two line numbers to current OUTDST mask
- HLIST [start line number [, end line number]] - list only to host ports
- PLIST [start line number [, end line number]] - list only to printer port
- CLS - clear screen
- INSRC mask expression - sets input (keyboard: bit 0, usb host: bit 1, serial host: bit 2, printer port: bit 3) defaults to keyboard + usb host (1 + 2 = 3). Be careful to not lock yourself out.
- OUTDST mask expression - sets output (screen: bit 0, usb host: bit 1, serial host: bit 2, printer port: bit 3) defaults to screen + usb host (1 + 2 = 3)
- REBOOT - reset computer (deletes current program)
- HELP - list commands and functions
File IO/SD Card
- FILES - lists the files on the SD card
- LOAD filename.bas - loads a file from the SD card
- CHAIN filename.bas - equivalent of: new, load filename.bas, run
- SAVE filename.bas - saves the current program to the SD card, overwriting
- ERASE filename.bas - delete the file on the SD card
- MKDIR dirname - Make a directory
- RMDIR dirname - Remove a directory
- DNDIR dirname - Enter a directory
- UPDIR - Exit the current directory
- DATA@ address expression, val [,val…] - loads data into memory at the specified address for access by PEEK or POKE. val are 8-bit numbers (0-255). Address must be non-zero and located above the last line of code (PEND) but below the stack
- PEEK( address expression) - get a value in memory
- POKE address expression, data expression - set a value in memory
- PRINT expression - print out the expression, also "?"
- INPUT variable - read a number into the variable
- REM stuff - remark/comment, also "'"
- PCHR expression - print a specified character
- INCHR variable [, delay expression] - returns the ASCII value of a key from the incoming buffer to a variable. By default it will wait until a key is pressed. An optional expression can set a timeout in mSec to wait before returning. If no key was pressed before returning it will return 0 in the variable.
- CURSOR row expression, col expression - set the cursor to a specific screen location (0-based)
- A=V, LET A=V - assign value to a variable
- +, -, *, / - Math
- &, |, ^ - Logic (AND, OR, XOR)
- <,<=,=,<>,!=,>=,> - Comparisons
- ABS( expression ) - returns the absolute value of the expression
- RSEED( v ) - sets the random seed to v
- RND( m ) - returns a random number from 0 to m
- PEND - returns the address of the first byte past the last line of the program
- DELAY timems expression - wait (in milliseconds)
- IF expression statement - perform statement if expression is true
- FOR variable = start TO end - start for block
- FOR variable = start TO end STEP value - start for block with step
- NEXT variable - end of for block
- GOTO linenumber - continue execution at this line number
- GOSUB linenumber - call a subroutine at this line number
- RETURN - return from a subroutine
- DWRITE pin,value - set pin with a value (HIGH,HI,LOW,LO)
- AWRITE pin,value - set pin with analog value (pwm) 0..255
- DREAD( pin ) - get the value of the pin
- AREAD( analogPin ) - get the value of the analog pin 0..1023 for 0-3.3Vin
DWRITE, AREAD IO pin is [0:8]. AWRITE pin is [0:2] that are on IO pins [6:8]. Do not drive any pin with more than 3.3 volts.