A minimal BASIC interpreter for Arduino UNO (ATmega328P)
nanoBASIC UNO is a minimal BASIC interpreter developed by shachi-lab for 8-bit AVR microcontrollers (Arduino UNO / ATmega328P).
It is a modern reconstruction of the original BASIC interpreter written in 2012 for the STM8S platform, redesigned with a clean architecture and reimplemented for today's MCU environments.
The goal of this project is to provide a compact, practical BASIC environment for small microcontrollers, using only minimal memory.
日本語版READMEはこちら → README_jp.md

Example run of nanoBASIC UNO. After the startup banner (Ver 0.14),
it demonstrates multiple statements on one line, a FOR/NEXT loop,
and a simple LED blink routine using Arduino UNO’s built-in D13 pin.
The Ctrl-C break behavior is also shown.
A command-line (CLI) version of nanoBASIC UNO is available.
You can try nanoBASIC UNO without an actual Arduino UNO board. The CLI version can be built on Windows and Linux.
See the cli/ directory for details.
- Minimal BASIC interpreter architecture
- Line numbers behave as labels
- Intermediate bytecode virtual machine
- Recursive-descent expression parser
- Runs on Arduino UNO (ATmega328P)
- REPL Mode / Run Mode suported
- GPIO / ADC / PWM / TICK / INKEY supported
- Includes classic BASIC features such as DATA / READ / RESTORE
- Supports modern operators such as += / -= / <<= / >>= / && / ||
- SAVE / LOAD to store and load programs,
with support for AutoRun - 16-bit / 32-bit integer support
(build-time selectable) - REPL line editing and command history
- UTF-8 support for comments and strings
- C-style string escape sequences
- Hardware-dependent components are isolated in a BIOS layer (bios_uno.cpp)
- Clean, portable header structure
- MIT License
Start here if you want to run nanoBASIC UNO immediately.
-
Quick Start (English)
→ docs/QuickStart_en.md -
クイックスタートガイド(日本語版)
→ docs/QuickStart_jp.md
Sample programs are included for hands-on learning.
Just copy, paste, and run them.
For details, see the sample programs here:
- Sample programs (English)
docs/nano_basic_samples_en.md - サンプルプログラム (日本語版)
docs/nano_basic_samples_jp.md
-
Reference Manual (English)
→ docs/nanoBASIC_UNO_Reference_Manual_en.md -
リファレンスマニュアル(日本語版)
→ docs/nanoBASIC_UNO_Reference_Manual_ja.md
/ (project root)
├── cli
| ├── bios_uno_cli.cpp # Windows/Linux hardware layer API
| ├── main.cpp # Windows/Linux entry point
| ├── README.mdnanoBASIC_UNO_Reference_Manual_en
| └── README_jp.md
├── docs
| ├── QuickStart_en.md
| ├── QuickStart_jp.md
| ├── nanoBASIC_UNO_Reference_Manual_en.md
| ├── nanoBASIC_UNO_Reference_Manual_jp.md
| ├── nano_basic_samples_en.md.md
| └── nano_basic_samples_jp.md.md
├── examples
| └── ...
├── src
| ├── nano_basic_defs.h # Language specification (platform-independent)
| ├── nano_basic_uno_conf.h # UNO-specific configuration & version info
| ├── nano_basic_uno.h # Minimal Arduino API (basicInit / basicMain)
| ├── nano_basic_uno.cpp # Interpreter core
| ├── bios_uno.cpp # Arduino UNO hardware layer
| └── bios_uno.h # hardware layer API
├── nanoBASIC_UNO.ino # Arduino entry point
├── README.md
├── README_jp.md
└── LICENSE.md
-
convertInternalCode()Converts BASIC source lines into tokenized internal code -
interpreterMain()Internal bytecode execution loop -
expr()and related functions Recursive-descent expression evaluation
All UNO-dependent hardware access is isolated in bios_uno.cpp:
- Digital I/O
- ADC
- PWM
- Random number generation
- System tick
- Serial I/O
For porting to other MCUs, replacing bios_uno.cpp / bios_uno.h is sufficient.
To optimize for the ATmega328P architecture, some string-handling logic uses AVR-specific PROGMEM access.
Because AVR uses a Harvard architecture (Flash and RAM are fully separate):
- Strings are stored in PROGMEM
- Access performed via
pgm_read_byte() F("...")macro reduces RAM consumption- Functions such as
printStringFlash()handle Flash-resident strings
On MCUs where Flash and RAM share a unified address space (e.g., ESP32 / ARM / RP2040):
- Replace PROGMEM usage with normal RAM strings
- Remove
pgm_read_byte() - Abstract string access similar to the BIOS layer
nanoBASIC is designed to work correctly even on MCUs
that do not support unaligned pointer access.
Except for AVR-specific string storage, the NanoBASIC core is largely platform-independent.
Open nanoBASIC_UNO.ino.
Select Arduino UNO and upload.
Configure the serial monitor as follows:
- 115200 baud
- CR+LF
Startup message:
nanoBASIC UNO Ver 0.18
OK
NanoBASIC UNO provides two execution modes.
Upon startup, each input line is executed immediately and not saved to the program area.
? 120+3
123
OK
Variables and multiple statements are also allowed:
A=2:FOR I=1 TO 3:? I*A:NEXT
2
4
6
OK
For storing multiple program lines, enter:
PROG
>DO
>OUTP 13,1
>DELAY 500
>OUTP 13,0
>DELAY 500
>LOOP
>#
RUN
# ends PROG mode.
Entered lines are stored in RAM and executed via RUN.
Note: Program memory exists only in RAM and is cleared on reset.
While a program is running, pressing Ctrl-C in the serial terminal
immediately aborts the execution.
This behaves the same as issuing STOP.
Useful for breaking out of long or accidental infinite loops.
Command names, statements, and function names are not case-sensitive.
For example, PRINT, print, and PrInT are treated the same.
| Statement | Meaning |
|---|---|
| Output | |
| INPUT | Input |
| GOTO | Jump to line number |
| GOSUB / RETURN | Subroutine |
| FOR / NEXT | Counting loop |
| DO / LOOP / WHILE | Conditional loop |
| CONTINUE / EXIT | Loop modifiers |
| IF / ELSEIF / ELSE / ENDIF | Conditional branching |
| DATA / READ / RESTORE | Data table handling |
| OUTP | Digital output |
| PWM | PWM output |
| DELAY / PAUSE | Delay |
| END / STOP | Terminate / break execution |
| RESUME | Resume from STOP/BREAK |
| RESET | System control |
| RUN / NEW | Program control |
| PROG / LIST / SAVE / LOAD | Program management |
| RANDOMIZE | Initialize random generator |
| Function | Meaning |
|---|---|
| ABS() | Absolute value |
| INP() | Digital input |
| ADC() | Analog input |
| RND() | Random number |
| INKEY() | Serial input buffer |
| Valiable | Meaning |
|---|---|
| TICK | System time (ms) |
| Operator | Meaning |
|---|---|
| +, -, *, /, % | Arithmetic |
| -, !, ~ | Unary ops |
| &, |, ^ | Bitwise ops |
| &&, || | Logical ops |
| <<, >> | Shift ops |
| =, ==, <>, <=, >=, <, != | Comparison |
Parentheses override standard operator precedence.
nanoBASIC uses 16-bit signed integers (-32768 to 32767).
Depending on the build configuration, nanoBASIC can also be built to use 32-bit integers.
No floating-point support.
Overflow is not checked.
- Default: decimal
0x1234: hexadecimal
A=10
B=0xBEEF
- General variables: A–Z (single-letter)
- Array variable: @[0]–@[63]
Z=10
@[1]=0
Assignments use the form:
A=(B+10)*5
Compound assignments are also supported. +=、 =、 *=、 /=、 %=、 |=、 &=、 ^= 、 <<=、 >>=
A<<=2
Appending "++" or "--" to a variable increments or decrements its value by 1.
A++
This increases the value of variable A by 1.
Note:
Increment and decrement operators cannot be used inside expressions.
They may appear only directly after a variable.
Strings may be used only inside PRINT (or '?'). C-style escape sequences and UTF-8 characters are supported in strings.
PRINT "Hello!\n"
Hello!
OK
A=5:? "A="A*2
A=10
OK
String variables do not exist.
In IF and WHILE, conditions are evaluated as:
- 0 → false
- non-zero → true
Comparison operators are optional; any numeric expression can act as a condition.
A single quote ' begins a comment that continues to the end of the line.
It may appear after a statement separator ":" to create inline comments.
OUTP 13,1 :' LED ON
Issues and Pull Requests are welcome. Suggestions for improvements or MCU porting are highly encouraged.
- nanoBASIC UNO may receive additional features or improvements in future releases.
- We are considering possible ports to other platforms in the future.
MIT License Copyright (c) 2025 shachi-lab
See LICENSE.md for details.