Getting Started
KEC Lisp builds to a single command-line tool, kec, that runs on a normal
computer — no KN-86 hardware required.
Get the source
Clone the repository from GitHub:
git clone https://github.com/Kinoshita-Electronics-Consortium/kec-lisp.gitcd kec-lispBuild
You need CMake and a C compiler.
cmake -S . -B build # configure (Release by default)cmake --build build # build → build/kecThat produces build/kec. Run the test suite to confirm everything works:
ctest --test-dir build --output-on-failureThe kec CLI
kec # REPLkec run FILE [args...] # run a script; args reach Lisp via (args)kec eval "EXPR" # evaluate one expression, print the resultkec build FILE [-o OUT] # inline top-level loads, parse-check, write one .keckec test [FILE...] # run the harness over FILE(s), or the whole suiteA quick taste:
$ kec eval '(map (fn (x) (* x x)) (range 1 6))'(1 4 9 16 25)
kec buildis not a compiler. Fe is a tree-walking interpreter —kec buildinlines top-level literal(load "...")forms, checks that the whole program parses, and writes a single self-contained.kecfile you cankec run.
Your first program
Put this in hello.lsp:
(defn fizzbuzz (n) (dotimes (i n) (let k (+ i 1)) (princ (cond ((is (mod k 15) 0) "FizzBuzz") ((is (mod k 3) 0) "Fizz") ((is (mod k 5) 0) "Buzz") (else (number->string k)))) (newline)))(fizzbuzz 15)…and run it:
kec run hello.lspA few things worth knowing
- Bind with
define,defn, orlet. Mutate withset. Compare with=(or its alias==). nilis the only false value, and also the empty list. There are no other booleans —0and""are both true.- Numbers are single-precision floats; integers are exact only within ±2²⁴.
- Use
equal?for element-by-element list comparison;is/=on two pairs check identity, not contents.
The full story is in the Language Reference.
Hacking on the standard library
Core (core/*.lsp) is baked into the kec binary at build time, so a Core edit
normally needs a rebuild. While iterating, point the CLI at the source files
instead:
KEC_CORE_DIR=$PWD/core ./build/kec eval '(your-core-fn ...)'The CLI re-loads those .lsp files (in NN- name order) over the embedded Core
at startup, so adding or changing definitions takes effect with no rebuild. It
layers over the baked-in copy — a definition you delete lingers until you
rebuild. Dev convenience only; the embedded Core is what ships and what the
firmware vendors.