Go to file
alexis 133f367843 Add arrays 2022-06-12 19:36:18 -06:00
arl Add arrays 2022-06-12 19:36:18 -06:00
ca1 More firmware work 2022-06-12 18:49:45 -06:00
libmpdec Clean up the c- stuff 2022-06-06 19:13:10 -06:00
subprojects Clean up the c- stuff 2022-06-06 19:13:10 -06:00
targets More firmware work 2022-06-12 18:49:45 -06:00
.gitmodules Clean up the c- stuff 2022-06-06 19:13:10 -06:00 Add arrays 2022-06-12 19:36:18 -06:00 Add arrays 2022-06-12 19:36:18 -06:00 More firmware work 2022-06-12 18:49:45 -06:00 Fix a few bugs 2022-05-29 18:38:58 -06:00
lextest.arl Isolate just the fw 2022-05-22 18:23:47 -06:00 Shut up the warnings 2022-06-06 19:20:56 -06:00
meson_options.txt ca-1 builds (not properly) 2022-05-28 18:31:35 -06:00


ARL (Alexis' Reverse LISP) is a stack-based language similar to RPL. CAOS is a CAlculator Operating System consisting of the ARL interpreter and a user interface written in ARL.

Building and loading the interpreter

Building requires meson, ninja, and a compiler for the target platform.

  • ./ unix to build for unix-like systems
  • ./ ca1 to build the CA-1 firmware.

The unix build has some useful command-line options for local testing.

The CA-1 build requires m68k-elf-gcc on the path. The CA-1 also requires a bootloader. It uses a6boot which is a UART flash bootloader for m68k. Prebuilt images of the bootloader are provided in ./targets/ca1. Use bootloader.hex to flash onto a chip directly using an external flash programmer; use bootloader_inplace.srec to flash the bootloader with itself (note this is dangerous - there is no protection against corrupting itself if it crashes!).

The CA-1 build will emit three .srec files for use with this bootloader: arl.srec containing the interpreter, ca1.srec containing the calculator ARL code, and full.srec containing both. Once the full image has been flashed once, the CA-1 ARL code may be updated by itself by reflashing only ca1.srec; this is much faster. Note that the offset of this in flash depends on the build so this can only be used if the interpreter code did not change.

ARL basic intro

ARL is stack-based. Your program is run simply by parsing tokens in sequence and executing them. If they define data, it is pushed to the stack; if they specify code, it is executed.

"Hello, world!\n" puts

This simple sequence first pushes the string "Hello, world!\n" to the stack, then looks up the word puts and executes the attached function.

Data types

ARL is dynamically typed and garbage-collected. The following data types are defined:

  • int is a 64-bit signed integer. Integers start with #, an optional radix specifier (x, b, or o), then the number. C-style character literals are also integers. Examples include: #-4321, #xFFFE, #b10101, 'f'.

  • real is a decimal floating point type implemented by a forked libmpdec. Syntax looks like the typical numeric/floating point syntax: 1234, -69.420, 1.337e3. When a real and an int collide, the result is a real. ARL's default precision can fully represent all possible int values as real.

  • complex is a pair of reals forming a complex number, with a j between: 0.707j-0.707. (This is not implemented yet.)

  • string is a string of ASCII characters or bytes. A string is not considered a scalar so it may not be contained in a vector. Strings know their length, so zero is valid content. Syntax is like C strings.

  • list is a list of values. In memory, they are stored as a linked list. Syntax is a series of values in braces: { 1 2 3 4 }. List contents may be any type and they need not be homogeneous: { 1 #2 j3,4 { 5 6 } }. List are created by executing the code between braces in a new stack, so you can calculate list contents in-place: { 1 dup dup + dup dup + } is {1 2 4}.

  • array is a fixed-size 1D or 2D array. Created with the array word.

  • program is an ARL program, which may itself be held on the stack. It is contained between double angle brackets: << sq swap sq + sqrt >> (This is not implemented yet.)

Non-scalars (string, list, vector, program) are held by reference, not by value. If you duplicate one you have two pointers to the same object. A copy word is provided to make a clone. (This is not implemented yet.)


Words are defined with Forth-like syntax: a colon, then the name, then the definition, then a semicolon: :hypot sq swap sq + sqrt;

Because ARL has very sparse syntax and most operators are implemented as words, most characters are valid in an identifier. Reserved byte values are:

  • ASCII control characters: bytes 0 through 31.
  • 0 through 9 and . but only at the beginning of a word.
  • : or ; which delimit definitions.
  • @, #, $, ' which are reserved type sigils.
  • ( and ) which create comments.
  • {, [, ], and } which create lists and vectors.
  • Whitespace characters: , \f, \n, \r, \t, \v

The following additional contraint applies: << or >> at the beginning of a token is always parsed as the syntactic feature, not a word. <<< for example is parsed the same as << <.

For a list of words built into ARL, see

Program and variable definition

  • :: Define a word. Forth-style syntax: :name statements...;. Added to the global namespace.

  • ->: Evaluate a series of variable names after this word, then pop a value from the stack for each one and define it in a new local with this name (2 3 -> two three). Parsing of variable names stops at the first non-word or a newline.

    Control statement "mini-scopes" (if, for, while) can read and write locals already defined in the parent scope, but any locals they newly define are lost when they go out of scope (like C).