pibasic

8 min read Original article ↗

Pi BASIC Interpreter

A modern, lightweight BASIC interpreter written in C, designed to run on any Linux system — from a standard PC down to a Raspberry Pi. It follows classic BASIC syntax closely while adding capabilities that make it genuinely useful for scripting, education, data processing, and embedded hardware projects.


Features at a Glance

Category Highlights
Language Dynamic and strict typing, full expression engine, all loop types, recursion, BYREF
Data Structures Arrays (47-function library), Dictionaries, 2D Matrices
String Processing 40+ string functions, full Regex library (PCRE2)
Cryptography MD5, SHA-1, SHA-256, HMAC, AES-128/192/256 (ECB/CBC/CTR), Base64, CRC32
Networking HTTP/HTTPS client (GET/POST/PUT/PATCH/DELETE), WebSocket client/server
Data Formats JSON parser/generator, CSV parser/writer with auto-delimiter detection
File System 30+ file and directory functions
Concurrency Threads, mutexes, semaphores, condition variables, lock-free atomics
Hardware GPIO, PWM, I2C, SPI (Raspberry Pi)
System Shell execution, system info, process control, user/group management
FFI Load and call functions from any .so shared library at runtime
Developer UX Interactive REPL with history, library import system

Language

Syntax and Types

  • Traditional BASIC syntaxLET is optional, identifiers are case-insensitive, comments with ' or REM
  • Six data typesNUMBER (double-precision float), INTEGER (64-bit signed), BOOLEAN, STRING, arrays, dictionaries
  • Optional strict typingDIM name AS TYPE enforces a type at runtime; omit for fully dynamic variables
  • Type keywordsNUMBER = DOUBLE = FLOAT; INTEGER = INT; BOOLEAN = BOOL
  • Single-quote strings'text' as an alternative to "text"

Control Flow

  • IF / ELSE IF / ELSE / END IFELSEIF and ENDIF also accepted
  • FOR / NEXT with optional STEP
  • WHILE / WEND
  • DO / LOOP WHILE|UNTIL
  • SELECT CASE — with TO ranges, multiple values per CASE, and CASE ELSE
  • BREAK and CONTINUE — work in every loop type

Functions

  • User-defined functions with local scoping and the GLOBAL keyword
  • Pass-by-value (default) and pass-by-reference (BYREF) for scalars, arrays, and dictionaries
  • Recursion up to 50 levels deep
  • Functions can return arrays and dictionaries

Library System

IMPORT "file.bas" / INCLUDE "file.bas" — execute a BASIC file in-place, making all its functions and variables available to the importing program.


Data Structures

Arrays

Declared with DIM name[size] or DIM name[size] AS TYPE. A 47-function built-in library covers:

  • ManipulationARR_PUSH, ARR_POP, ARR_SHIFT, ARR_UNSHIFT, ARR_INSERT, ARR_REMOVE, ARR_REVERSE, ARR_SWAP
  • SortingARR_SORT_ASC, ARR_SORT_DESC, ARR_SORT_NUM_ASC, ARR_SORT_NUM_DESC
  • SearchARR_FIND, ARR_FIND_LAST, ARR_BINARY_SEARCH, ARR_CONTAINS
  • StatisticsARR_SUM, ARR_AVG, ARR_MIN, ARR_MAX, ARR_MEDIAN, ARR_STDEV, ARR_PERCENTILE
  • Set operationsARR_UNION, ARR_INTERSECT, ARR_DIFF, ARR_UNIQUE
  • GenerationARR_RANGE, ARR_FILL, ARR_LINSPACE
  • TransformationARR_SLICE, ARR_COPY, ARR_CONCAT, ARR_FLATTEN, ARR_MAP, ARR_FILTER

Dictionaries

Declared with DIM name AS NEW DICTIONARY. Key-value store with string keys, supporting optional typed values and a full DICT_* function set.

Matrices

2-D arrays declared with DIM name[rows][cols], with a dedicated MAT_* library:

  • CreationMAT_ZEROS, MAT_ONES, MAT_IDENTITY, MAT_FILL, MAT_COPY
  • ArithmeticMAT_ADD, MAT_SUB, MAT_MUL, MAT_HADAMARD, MAT_SCALE, MAT_DOT
  • Linear algebraMAT_DET, MAT_TRANSPOSE, MAT_TRACE, MAT_FROBENIUS
  • AggregationMAT_SUM, MAT_MIN, MAT_MAX
  • UtilitiesMAT_RESHAPE, MAT_ROW, MAT_COL, MAT_PRINT, MAT_EQUAL

Built-in Libraries

String Library (40+ functions)

SUBSTR, REPLACE, REPLACE_FIRST, REMOVE, SPLIT / SPLIT_COUNT / SPLIT_GET, JOIN, TRIM, LTRIM, RTRIM, TRIM_CHARS, UPPER, LOWER, TITLE, SWAPCASE, PADLEFT, PADRIGHT, PADCENTER, FIND, FIND_FROM, LAST_INSTR, COUNT_STR, REPEAT, REVERSE, FORMAT (printf-style), STR_CMP, STR_ICMP, HEX_ENCODE, HEX_DECODE, BASE64_ENCODE, BASE64_DECODE, STR_HASH

Predicates: ISNUMERIC, ISALPHA, ISALNUM, ISSPACE, ISUPPER, ISLOWER, ISDIGIT

Math Library

Full trigonometry (SIN, COS, TAN, ASIN, ACOS, ATAN, ATAN2, COT, CSC, SEC), hyperbolic functions, logarithms (LOG, LOG2, LOG10, LOG_BASE, LOG1P), rounding (FLOOR, CEIL, ROUND, TRUNC), ABS, SIGN, CLAMP, HYPOT, DEG, RAD, PI, E, MAP_RANGE, LERP, IS_EVEN, IS_ODD, IS_PRIME, GCD, LCM, FACTORIAL, GAMMA, BETA, ERF

Date/Time Library

DATE(), TIME(), TIMESTAMP(), TIMER(), MICROS(), FORMAT_TIME(), FORMAT_TS(), DATETIME_STR(), TIME_AGO(), SLEEP(), SLEEP_MS(), SLEEP_US(), timestamp arithmetic (TIME_ADD_DAY, TIME_ADD_HOUR, TIME_DIFF, …), calendar helpers (IS_LEAP_YEAR, DAYS_IN_MONTH, MONTH_NAME, WEEKDAY_NAME, ISO_WEEK), UTC functions (UTC_DATETIME, UTC_TIMESTAMP, UTC_HOUR, UTC_OFFSET)

Regular Expressions (PCRE2)

Full Perl-compatible regex engine:

REGEX_MATCH, REGEX_MATCH_FULL, REGEX_FIND, REGEX_FIND_ALL, REGEX_REPLACE, REGEX_REPLACE_ALL, REGEX_SPLIT, REGEX_GROUP, REGEX_NAMED_GROUP, REGEX_COUNT

JSON

Built-in parser and generator. Parsed JSON is flattened into a Dictionary using dot-notation for objects (user.name) and bracket-notation for arrays (tags[0]).

JSON_PARSE, JSON_GET, JSON_VALID, JSON_STRINGIFY

CSV

Auto-detects delimiter (, ; tab). Handles quoted fields, embedded delimiters, and escaped quotes. Data stored in a Dictionary for fast row/column access by name.

CSV_PARSE, CSV_LOAD, CSV_STRINGIFY, CSV_SAVE, CSV_ROWS, CSV_COLS, CSV_GET, CSV_SET, CSV_HEADER, CSV_ADDROW

Cryptography

Pure-C implementation with no external dependencies:

  • HashingCRYPTO_MD5, CRYPTO_SHA1, CRYPTO_SHA256, CRYPTO_HMAC_SHA256, CRYPTO_CRC32
  • EncodingCRYPTO_BASE64_ENC, CRYPTO_BASE64_DEC, CRYPTO_HEX_ENC, CRYPTO_HEX_DEC
  • Symmetric encryption — AES-128/192/256 in ECB, CBC, and CTR modes
  • Key generationCRYPTO_AES_KEYGEN(bits), CRYPTO_AES_IV()
  • UtilitiesCRYPTO_XOR, CRYPTO_ROT13, CRYPTO_RAND_BYTES, CRYPTO_RAND_INT

Networking

HTTP Client

Full HTTP/HTTPS client backed by libcurl (libcurl.so.4), loaded at runtime — present by default on Raspberry Pi OS, Debian, and Ubuntu. No libcurl headers are required to compile.

  • MethodsNET_GET, NET_POST, NET_PUT, NET_PATCH, NET_DELETE
  • Status and headersNET_STATUS, NET_HEADER, NET_HEADERS_CLEAR, NET_RESPONSE_HEADER
  • ConvenienceNET_SET_BEARER, NET_SET_CONTENT_TYPE, NET_SET_TIMEOUT
  • EncodingNET_ESCAPE, NET_UNESCAPE

WebSocket

Built-in client and server with unlimited concurrent connections (fully dynamic allocation):

WS_CONNECT, WS_LISTEN, WS_SEND, WS_RECV, WS_POLL, WS_CLOSE, WS_BROADCAST, WS_CLIENT_COUNT, WS_SERVER_RUNNING, WS_CLIENT_IP, WS_PING, WS_KICK_ALL


Concurrency

Full POSIX-based multithreading. All internal tables are dynamically sized — there is no fixed upper limit on the number of threads, mutexes, semaphores, or condition variables. Each thread receives a private copy of the interpreter state; shared state is coordinated through the primitives below.

  • ThreadsTHREAD_CREATE, THREAD_JOIN, THREAD_DETACH, THREAD_RUNNING, THREAD_SELF
  • MutexesMUTEX_CREATE, MUTEX_LOCK, MUTEX_UNLOCK, MUTEX_TRYLOCK, MUTEX_DESTROY
  • SemaphoresSEM_CREATE, SEM_WAIT, SEM_POST, SEM_TRYWAIT, SEM_DESTROY
  • Condition variablesCOND_CREATE, COND_WAIT, COND_SIGNAL, COND_BROADCAST, COND_TIMEDWAIT, COND_DESTROY
  • Lock-free atomicsATOMIC_INC, ATOMIC_DEC, ATOMIC_ADD, ATOMIC_GET, ATOMIC_SET, ATOMIC_CAS

Hardware (Raspberry Pi)

Requires appropriate kernel modules and device permissions (typically root or membership in the gpio / spi / i2c groups).

  • GPIOGPIO_SETUP, GPIO_WRITE, GPIO_READ
  • PWMPWM_SETUP, PWM_WRITE
  • I2CI2C_SETUP, I2C_WRITE, I2C_READ
  • SPISPI_SETUP, SPI_READ, SPI_WRITE, SPI_TRANSFER, SPI_CLOSE
  • TimingDELAY (ms), DELAY_MICRO (µs)

System and Unix

  • Shell executionEXEC, EXEC_OUT, EXEC_ERR, EXEC_FULL
  • System infoUNAME, HOSTNAME, UPTIME, UPTIME_STR, LOADAVG, CPU_COUNT, MEM_TOTAL, MEM_FREE
  • Process controlKILL, KILL_NAME, GETPID, GETENV, SETENV, UNSETENV
  • User managementUSER_ADD, USER_ADD_FULL, USER_DEL, USER_DEL_FULL, USER_MOD, USER_EXISTS, USER_LIST, USER_INFO, PASSWD, WHOAMI
  • Group managementGROUP_ADD, GROUP_DEL, GROUP_MOD, GROUP_EXISTS, GROUP_LIST, GROUP_ADD_USER, GROUP_DEL_USER, GROUP_MEMBERS

FFI — C Library Integration

Load any .so shared library at runtime and call its functions directly from BASIC — no recompilation required.

  • LIBLOAD "libname.so" — load a shared library
  • LIBCALL("lib.so", "func", arg, …) — call a function returning a number
  • LIBCALL_STR("lib.so", "func", arg, …) — call a function returning a string
  • LIBFREE "libname.so" — unload a library
  • LIBLOADED("libname.so") — check if a library is currently loaded
  • LIBLIST — list all loaded libraries

Introspection

  • ISDEF(name), ISARRAY(name), ISDICT(name), ISFUNCTION(name) — test what a name refers to
  • TYPEOF(expr) — returns "NUMBER", "INTEGER", "STRING", or "BOOLEAN"
  • ISDYNAMIC(name) / ISSTATIC(name) — test whether a variable has a type constraint

Building

Requirements: GCC or any C99-compatible compiler, make, standard C library. For regex: libpcre2-dev. For HTTP: libcurl at runtime (no headers needed to build).

git clone https://codeberg.org/alimiracle/pibasic
cd pibasic
make

Produces a single executable: pibasic.

make debug      # build with full warnings and debug symbols
make clean      # remove build artifacts

Usage

./pibasic program.bas   # run a program file
./pibasic               # start the interactive REPL

Makefile shortcuts:

make run                     # start the REPL
make run-file FILE=prog.bas  # run a specific file

Interactive REPL

Start the interpreter with no arguments. The REPL supports:

  • Command history with arrow keys
  • Multi-line buffering — the REPL waits for a closing keyword (END FUNCTION, NEXT, WEND, END IF, etc.) before executing
  • Ctrl+C to cancel the current input buffer
  • Ctrl+D to exit

Documentation

The full language reference — covering every function, every error message, and 48 worked examples — is in guide.md.


Privileges

GPIO / PWM / I2C / SPI require appropriate kernel modules and device permissions on Raspberry Pi.

User and group management — write operations (USER_ADD, USER_DEL, USER_MOD, PASSWD, GROUP_* write functions) require root. Read-only queries (USER_EXISTS, USER_LIST, USER_INFO, WHOAMI, GROUP_EXISTS, GROUP_LIST, GROUP_MEMBERS) work as any user.

Shell executionEXEC, EXEC_OUT, EXEC_ERR, and EXEC_FULL pass commands to /bin/sh. Sanitize any user-supplied input before passing it to these functions.


Contributing

Contributions are welcome. Please open an issue before submitting a large pull request so the change can be discussed first. For bug reports, include:

  • The .bas program that reproduces the issue
  • Compiler version (gcc --version)
  • Platform (OS + architecture)

License

Licensed under the GNU General Public License v3.0. See LICENSE for the full text, or visit https://www.gnu.org/licenses/gpl-3.0.html.

You are free to use, study, modify, and distribute this software under the terms of the GPL v3. Any derivative work must also be distributed under the same license.