How to compile Stefan's BASIC (and how it works) - slviajero/tinybasic GitHub Wiki

Basic Version 2.x

Arduino, ESP and the likes

Import the folder IoTBasic to the Arduino IDE. You may want to check and edit the files language.h to select the language features you want and then hardware.h for the hardware features. For a quick start, no complicated configuration is needed any more in these files. There are heuristics chossing the right language set and basic hardware configurations for you. Just compile and upload.

The small Arduino platforms like the UNO will get an Integer BASIC and have EEPROM support predefined. Bigger boards like the Mega and above will have the full BASIC language set, which means a floating point BASIC with many features.

ESP boards will have a SPIFF filesystem, RP2040 a LittleFS filesystem predefined.

The definitions for the hardware and the language are identical to the 1.x versions. They can be set by hand. To do this undef the macro HARDWAREHEURISTICS in hardware.h and LANGUAGEHEURISTICS in language.h.

Mac, Linux, Windows MINGW and all the rest that can fork() and exec()

Compile basic.c with

gcc basic.c runtime.c -lm

after setting language and hardware definitions just like on Arduino. Also, the Raspberry specific functions are still there is described below.

On an Raspberry, depending on the Wiring library you use

gcc basic.c -lm -lwiringPi

or

gcc basic.c -lm -lpigpiod_lf2

will do the job.

MSDOS

MSDOS can be compiled with the Turbo C 2.0 compiler. Best use the prepared fileset in https://github.com/slviajero/tinybasic/tree/main/Basic2/MSDOS which is tested against the compiler in DOSBOX.

Command line is

tcc basic.c runtime.c

Basic Version 1.x

Arduino, ESP and the likes

Import the folder IoTBasic to the Arduino IDE. IotBasic.ino is strictly identical to basic.c of the POSIX OSes. In addition to this there are three more files. basic.h is the standard header file. It is identical to the basic.h of the POSIX OSes. All Arduino hardware and device specific code has been moved to hardware-arduino.h. In addition to it, there is wifisettings.h. T

For Arduino SAMD boards, RTCZero and RTCLowPower is needed. For STM32 boards, STM32RTC and STM32LowPower is needed. In both cases the libraries can be loaded with the library manager. Some platforms have additional library needs. Please look into the hardware section of this Wiki for more information.

Once you have imported to code to the Arduino IDE you can compile and upload. I mainly work with 1.8.19 and occasionally test with the 2.x and web versions of the IDE.

Mac, Linux, Windows MINGW and all the rest that can fork() and exec()

Originally the program came in one source file basic.c. There were no headers and all Arduino code was integrated in this one source file. After the code has grown to 8000 lines and the source file was 160 kB and growing, I decided to change this. Version 1.2.1 is the last released version with just one file.

From 1.3 the code comes as basic.c, basic.h and hardware-posix.h. These files can be compiled with gcc or the Arduino IDE. No makefile is needed.

On a Raspberry you want to set #define RASPPI and compile with

gcc basic.c -lm -lwiringPi

On other Linuxes and MINGW

gcc basic.c -lm

will do.

There is a binary for Rasp and Mac in the 1.3 release.

For Windows, MINGW is required: https://sourceforge.net/projects/mingw/

MSDOS

Slightly exotic port. Use the dosify script on a Mac on basic.c, basic.h, hardware-posix.h to generate the source code. hardware-posix.hshould be renamed hardware.h. This script adds CR and removes oneline comment. This file can be compiled with Turbo C version 2.01. It cannot be loaded in the editor because it is too big. The command line compiler tcc works well.

Version 1.3 runs on DOS and a binary will be supplied in the release. Version 1.4 fully test and CATALOG now working on DOS.

Common features of Basic Version 2.x and Basic 1.x

Language features

The language is build to be scalable from small to big. Which features are present is decided at compile time in the language feature section. This section in the code starts with

#undef BASICFULL

#undef BASICINTEGER

#define BASICSIMPLE

#undef BASICMINIMAL

#undef BASICSIMPLEWITHFLOAT

#undef BASICTINYWITHFLOAT

These 5 language sets are predefined. You can set one of them and ignore the individual settings. In BASIC 2 there is BASICSMALL as an additional feature - it is smaller than BASICSIMPLE.

  • BASICFULL: all language features are included and BASIC is floating point. This is essentially like the home computer BASICs of the past.
  • BASICINTEGER: like BASICFULL but with Integer arithmetic. The precision depends on the platform. 16 bit for AVR, most others 32bit. This can be changed on all platforms.
  • BASICSIMPLE: a smaller language set for AVR systems. Integer BASIC with many of the features needed to work on Arduino.
  • BASICMINIMAL: only the core language set. This is like the old days Tinybasic with a few Arduino functions.
  • BASICSIMPLEWITHFLOAT: a small floating point BASIC with many language sets. Ideal for an UNO.
  • TINYBASICWITHFLOAT: a very small floating point BASIC.

If you want to add and remove language features individual, you need to #undef all of the macros above and configure your language in the next section:

#define HASAPPLE1

#define HASARDUINOIO

#define HASFILEIO

#define HASTONE

#define HASPULSE

#define HASSTEFANSEXT

#define HASERRORMSG

#define HASVT52

#define HASFLOAT

#undef HASGRAPH

#define HASDARTMOUTH

#define HASDARKARTS

#define HASIOT

#define HASMULTIDIM

#define HASSTRINGARRAYS

#define HASTIMER

#define HASEVENTS

#define HASERRORHANDLING

#define HASMSTAB

#define HASARRAYLIMIT

#define HASSTRUCT

#define HASMSSTRINGS

#define HASMULTILINEFUNCTIONS

#define HASEDITOR

#define HASTINYBASICINPUT

#define HASLONGNAMES

#define HASHELP

If all of these macros are undef, the core language set is Palo Alto Tinybasic. Defining any of them adds functions:

  • HASAPPLE1: strings, 1d arrays, all commands related with it, logical expressions, peek and poke
  • HASARDUINOIO: writing und reading from analog and digital pins, millisecond time and delay function
  • HASFILEIO: commands to open and close files, reading and writing to files. This only makes sense if the target system has a filesystem. Otherwise the commands are all no operation but exist.
  • HASTONE: the Arduino tone function is included as the PLAY command.
  • HASPULSE: the Arduino pulseIn function is included as the PULSEIN function.
  • HASSTEFANSEXT: extensions I added to the language set and that I found important, some functions like SQR and POW (exponentation), GET and PUT for single character output, memory dump, and extension to FOR NEXT, CALL and USR.
  • HASERRORMSG: error messages.
  • HASV52: VT52 escape sequence handling for displays, only makes sense if the system has a display connected.
  • HASFLOAT: floating point support including the functions SIN, COS, TAN, ATAN, LOG, and EXP, please read more about number types further down.
  • HASGRAPH: graphics functions for displays.
  • HASDARTMOUTH: ON GOTO/GOSUB, DEF FN, DATA/READ/RESTORE commands present in the early BASIC standards
  • HASDARKARTS: low level interpreter functions accessible to the user with many side effects, MALLOC and FIND to allocate memory on the heap, EVAL to convert strings to command lines at runtime and execute them. CLR can delete variables.
  • HASIOT: string functions VAL, INSTR, STR to parse input, NETSTAT for network control, SLEEP for deep sleep modes. More features planned here.
  • HASMULTIDIM: 2d arrays.
  • HASSTRINGARRAYS: 1d arrays of strings. This is an extension of HASMULTIDIM.
  • HASTIMER: Run background timers and change the program flow with it
  • HASEVENTS: Change the program flow on interrupts and external events
  • HASERRORHANDLING: Change the program flow if errors occur
  • HASMSTAB: The TAB command works MS style
  • HASARRAYLIMIT: Array limits can be changed
  • HASSTRUCT: Structured programming with WHILE, UNTIL, SWITCH and block IF statements
  • HASMSSTRINGS: String function like MS i.e. RIGHT, LEFT, MID
  • HASMULTILINEFUNCTIONS: function can have many lines.
  • HASEDITOR: a simple line editor
  • HASTINYBASICINPUT: INPUT can take variables and formulae
  • HASLONGNAMES: long names for functions and variables
  • HASHELP: display the commands BASIC has.

The language features are fairly independent and can be activated in any combinations. There may be combinations which are more useful than others.

Memory size

After the language feature setting you will see a macro MEMSIZE. It is normally set to 0. A heuristic in the code will determine the right memory size at runtime using malloc() to allocate the BASIC memory. This will fail sometime and stability problems may arise. If this happens, the memory size can be hardwired here and the heuristic is deactivated. By default this is only done for very small boards directly in the code.

Hardware definitions

For setting the hardware features open hardware-arduino.h (BASIC 1.0) or hardware.h (BASIC 2.0 and above).

#undef ARDUINOPICOSERIAL

#undef ARDUINOPS2

#undef ARDUINOUSBKBD

#undef ARDUINOZX81KBD

#undef ARDUINOI2CKBD

#undef GIGAUSBKBD

#undef ARDUINOPRT

#undef DISPLAYCANSCROLL

#undef ARDUINOLCDI2C

#undef ARDUINONOKIA51

#undef ARDUINOILI9488

#undef ARDUINOSSD1306

#undef ARDUINOMCUFRIEND

#undef ARDUINOEDP47

#undef ARDUINOGRAPHDUMMY

#undef LCDSHIELD

#undef ARDUINOTFT

#undef ARDUINOVGA

#undef TFTESPI

#undef ARDUINOEEPROM

#undef ARDUINOI2CEEPROM

#undef ARDUINOEFS

#undef ARDUINOSD

#undef ESPSPIFFS

#undef ESP32FAT

#undef RP2040LITTLEFS

#undef STM32SDIO

#undef GIGAUSBFS

#undef ARDUINORTC

#undef ARDUINORTCEMULATION

#undef ARDUINOTONEEMULATION

#undef ARDUINOWIRE

#undef ARDUINOSIMPLEWIRE

#undef ARDUINOWIRESLAVE

#undef ARDUINORF24

#undef ARDUINOETH

#undef ARDUINOMQTT

#undef ARDUINOSENSORS

#undef ARDUINOSPIRAM

#undef STANDALONE

#undef STANDALONESECONDSERIAL

The BASIC interpreter code has quite a few device drivers and heuristics for typical hardware configurations build in. The macros in this section of the code steer these heuristics. In standard hardware configurations they should work without further chances of the code.

  • ARDUINOPICOSERIAL: use the picoserial for serial communications on Arduino 168 and 328 based platforms. Save memory and flash. Good for small systems. Only works on the 8bit AVR platforms with simple UARTS like Uno or Mega2560. Not very portable.
  • ARDUINOPS2: use a PS2 keyboard, there are standard pins defined for this which can be changed in the code. Needs the (patched) PS2Keyboard library.
  • ARDUINOUSBKBD: USB keyboards on a DUE. Very raw. Not tested well. German keymap included. Needs the KeyboardController library.
  • ARDUINOZX81KBD: the keyboard of the Sinclair ZX81 on an Arduino. Needs the ZX81Keyboard library.
  • ARDUINOI2CKBD: the serial keyboard of the T-Deck and other keyboards using I2C
  • GIGAUSBKBD: the USB keyboard of the GIGA board
  • ARDUINOPRT: activate a second serial port for printing or to connect other devices. Software Serial is used on Arduino UNO and Nano with some standard pins, DUE and MEGA use the existing second UART channel.
  • DISPLAYCANSCROLL: this setting is relevant in combination with the display definitions. In essence, it creates a screen buffer and handles refresh of displays.
  • ARDUINOLCDI2C: connect a display using the I2C port, supports 4x20 displays, can be adapted 2x16 or other dimensions. Needs the LiquidCrystal_I2C library.
  • ARDUINONOKIA51: Nokia LCDs connected with SPI. Needs U8g2lib.
  • ARDUINOILI9488: ILI9488 SPI display with 480x320 resolution. Needs Adafruit_GFX and the ILI9488 library.
  • ARDUINOSSD1306: small OLEDs with I2C interface. Needs U8g2lib.
  • ARDUINOMCUFRIEND: the standard parallel TFTs. Needs MCUFRIEND_kbv.
  • ARDUINOEDP47: experimental E-Paper support
  • ARDUINOGRAPHDUMMY: a graphics dummy. No operations for all graphics functions. Needed to test the code.
  • LCDSHIELD: support for the standard LCD shield, buttons and display functions are available in BASIC. Needs LiquidCrystal.
  • ARDUINOTFT: support of a SD1963 TFT display and CTE TFT shield for Arduino DUE and MEGA 256 including optionally the SD cards in the shield or display. Needs UTFT.
  • ARDUINOVGA: ESP32 VGA display with the TTGO VGA card version 1.4. Needs FabGL.
  • ARDUINOEEPROM: EEPROM support including external EEPROMS in real time clocks, can remain activated even if there is no EEPROM.
  • ARDUINOI2CEEPROM: serial EEPROMs on I2C.
  • ARDUINOEFS: activate external EEPROMS via I2C as a filesystem. Independent of ARDUINOEEPROM. Needs the EepromFS library.
  • ARDUINOSD: SD card filesystem support for Arduino MEGA 265, DUE, ESP8266 and ESP32. Low memory boards like the UNO and NANO are not supported.
  • ESPSPIFFS: SPIFFS filesystem support for the build in filesystem of an ESP8266 or ESP32. Cannot be used together with ARDUINOSD. You can have one or the other.
  • ESP32FAT: FAT filesystem on modern ESP32 boards
  • RP2040LITTLEFS: Little FS on RP2040 systems (and only on them).
  • STM32SDIO: support for SD cards on STM32F4 boards. These cards use the SDIO interface and need a special library STM32SD.
  • GIGAUSBFS: the USB filesystem of the GIGA board
  • ARDUINORTC: connect a DS3231 clock via I2C. Clock EEPROM access is supported. The EEPROM of the clock added to the internal EEPROM.
  • ARDUINORTCEMULATION: emulate a real time clock using the internal clock of the Arduino.
  • ARDUINOTONEEMULATION: emulate TONE in platforms that don't have if
  • ARDUINOWIRE: use I2C directly via the BASIC I/O logic (OPEN, CLOSE, ....)
  • ARDUINOSIMPLEWIRE: a simple Wire code without the file sytem
  • ARDUINOWIRESLAVE: act as a slave on the I2C bus.
  • ARDUINORF24: activate RF2401 wireless support - send and receive messages implemented. Needs the RF2401 library.
  • ARDUINOETH: use an Ethernet adapter for networking. Needs the Arduino Ethernet library.
  • ARDUINOMQTT: MQTT support and Wifi - under development. Needs the Pubsub MQTT library.
  • ARDUINOSENSORS: access some sensors directly. Please look at the sensor section of the Wiki.
  • ARDUINOSPIRAM: use an SPI RAM modules as BASIC memory.
  • STANDALONE: if a keyboard and a display is available STANDALONE makes these devices standard I/O channels
  • STANDALONESECONDSERIAL: use the second serial port as default port. Needed on some boards with USB serial features.

Special libraries needed by language feature.

Some boards need libraries to compile BASIC. These are:

  • RTCZero and RTCLowPower: for all SAMD boards.
  • SMT32RTC and SMT32LowPower: for all SMT32 boards.

Some hardware features require the following libraries not available through the Arduino library manager:

All other libraries mentioned above are standard Arduino libraries available through the library manager.

Internal number types

The BASIC interpreter can be used with different internal number types and lengths of number variables. They can be changes if there are special needs. You don't need to change anything here but you can. Only change the highlighted lines. The exact logic is controlled in this code section

#ifdef HASFLOAT

typedef float number_t;

const number_t maxnum=16777216;

#else

typedef int number_t;

const number_t maxnum=(number_t)~((number_t)1<<(sizeof(number_t)*8-1));

#endif

typedef unsigned short address_t;

const int numsize=sizeof(number_t);

const int addrsize=sizeof(address_t);

const int eheadersize=sizeof(address_t)+1;

**const int strindexsize=2; **

const address_t maxaddr=(address_t)(~0);

The core number type of the interpreter is number_t. This is what you see in the interpreter when you store numbers or calculate. All variables, arrays and numbers are number type. By default this is either float or int depending on the HASFLOAT macro. You can use any other type here like double or long if the type is signed and at least as long as address_t. It needs to be a type that the compiler can automatically cast to integer types.

The type address_t is not seen directly in the interpreter. It is used for addressing storage. The type is unsigned and has to be able to enumerate the entire memory. It can be smaller but never bigger in number of bytes than number_t.

With the default settings in the code and the compilers the following will happen

  • Arduino 8 bit systems: 16 bit signed integers or 32 bit floats as number type and 16 bit unsigned integers as for addressing storage. This is more then enough as the 8 bit systems have no more than 16kb RAM and 4 kb EEPROM.
  • 32 bit systems: 32 bit signed integers or 32 bit floats as number type and 16 bit unsigned integers for addressing storage limiting the address space to 64 kB.

If you want to address more storage you can change address_t to a 32bit type (i.e. unsigned int) on 32 bit systems as long as you keep number_t at least 32 bit. If you need higher accuracy on 8 bit or 32 bit systems you can use the longer types as number type. If you change a floating point number_t to a higher value you could also set maxnum to a higher value. maxnum is the biggest integer that can still be represented accurately in the floating point type. This is only needed in special cases.

A third parameter that can be customized here (although I don't recommend it) is strindexsize. This variable controls the number of bytes reserved in a string to store the length. The default setting is 2 bytes meaning that strings can be at most 65535 characters long. Any other value would also be possible as long as address_t can address the entire string.

To make things a little easier, HAS64BIT is a predefined macro. Setting it will change arithmetic to 64bit. HAS32BITINT changes integer BASICs to 32bit instead of 16 bit on 8bit controllers.

Maximum BASIC memory

Theoretical maximum memory is 64 kB if address_t is defined as a 16 bit quantity. Defining address type as a 32 bit quantity increases this into the MB range.