Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
55dc8f3
Change integers to long long
NJdevPro Oct 19, 2024
d69ef32
add >, >=, <=, exit, mod, not, and, or
NJdevPro Oct 24, 2024
a3649e7
Correct bugs in or, and and length
NJdevPro Oct 24, 2024
3c4fbf3
Add tests, remove -g in Makefile
NJdevPro Oct 24, 2024
d350765
Create c-cpp.yml
NJdevPro Oct 25, 2024
7ab35c5
Merge pull request #1 from NJdevPro/extend
NJdevPro Oct 25, 2024
773559b
Add REPL
NJdevPro Oct 26, 2024
b4bd2f9
Fix print
NJdevPro Oct 26, 2024
51bd17b
No longer quit after an error.
NJdevPro Oct 26, 2024
6951020
Modify README
NJdevPro Oct 26, 2024
a4624f4
Add REPL
NJdevPro Oct 26, 2024
0227267
Fix print
NJdevPro Oct 26, 2024
b91be6b
No longer quit after an error.
NJdevPro Oct 26, 2024
55fafe9
Modify README
NJdevPro Oct 26, 2024
1058a67
Update README.md
NJdevPro Oct 26, 2024
812617f
Add missing header
NJdevPro Oct 27, 2024
5860eab
Read files passed as input.
NJdevPro Oct 29, 2024
4e46708
Update repl.c
NJdevPro Oct 30, 2024
cf7c443
More details in README
NJdevPro Oct 30, 2024
25a0b66
Moved sources to src directory
NJdevPro Oct 30, 2024
103fea2
Add reverse
NJdevPro Oct 31, 2024
8096d88
Add reverse primitive
NJdevPro Oct 31, 2024
25d234b
Add missing file
NJdevPro Oct 31, 2024
855a6f9
Merge branch 'master' into extend
NJdevPro Oct 31, 2024
82b4f65
Moved sources under src
NJdevPro Oct 31, 2024
15171ad
Moved sources under src
NJdevPro Oct 31, 2024
1541b14
Can process several files.
NJdevPro Oct 31, 2024
7ba2db9
More details in README
NJdevPro Oct 30, 2024
10480ae
Moved sources to src directory
NJdevPro Oct 30, 2024
783e001
Add strings and string functions
NJdevPro Oct 31, 2024
8761982
Merge branch 'extend'
NJdevPro Oct 31, 2024
6c3d68b
Fix freeze.
NJdevPro Oct 31, 2024
84e9c84
Merge branch 'extend'
NJdevPro Oct 31, 2024
a5313aa
Make length and reverse operate on strings.
NJdevPro Nov 2, 2024
4aa868a
Add command line arguments parsing
NJdevPro Nov 3, 2024
c84076a
Add command line parameters
NJdevPro Nov 4, 2024
ff65094
Delete repl.h
NJdevPro Nov 4, 2024
a2d6779
Add file and line number to error messages
NJdevPro Nov 6, 2024
b5a1e59
Merge branch 'master' into extend
NJdevPro Nov 6, 2024
014f7b3
Add missing header
NJdevPro Nov 6, 2024
cf196d9
Merge pull request #2 from NJdevPro/extend
NJdevPro Nov 6, 2024
66864ff
Add new tests
NJdevPro Nov 6, 2024
1efacb7
Fix crash in comment
NJdevPro Nov 7, 2024
e2a4784
Rebase
NJdevPro Oct 30, 2024
d64c074
Update README
NJdevPro Oct 30, 2024
51547cb
Examples now load library.lisp
NJdevPro Nov 7, 2024
909263b
Remove files that shouldn't be tracked
NJdevPro Nov 7, 2024
3b305e8
Delete .vscode directory
NJdevPro Nov 7, 2024
ace8ad3
Coerce eq and string=.
NJdevPro Nov 8, 2024
201366b
Fix error messages.
NJdevPro Nov 8, 2024
e66fa67
Add reduce
NJdevPro Nov 8, 2024
cd14903
Merge pull request #3 from NJdevPro/extend
NJdevPro Nov 8, 2024
8247af3
Update README.md
NJdevPro Nov 8, 2024
3225bb5
Had to go backwards to fix the crash.
NJdevPro Nov 11, 2024
f019041
Merge pull request #4 from NJdevPro/extend
NJdevPro Nov 13, 2024
00d1bdf
Reintroduce atom and progn
NJdevPro Nov 14, 2024
e089772
Add /reset /memory
NJdevPro Nov 16, 2024
6fc80ac
Merge pull request #5 from NJdevPro/extend
NJdevPro Nov 16, 2024
6737a31
Update README.md
NJdevPro Nov 21, 2024
814397b
Fix memory corruption
NJdevPro Nov 29, 2024
129e13c
Fix non-regression test suite
NJdevPro Nov 29, 2024
a58a7ee
Merge branch 'master' into extend
NJdevPro Nov 29, 2024
04a3183
Merge pull request #6 from NJdevPro/extend
NJdevPro Nov 29, 2024
9deb0ca
Fix crash on file not found
NJdevPro Nov 30, 2024
2b05fb1
Add lisp primitive, remove and/or primitives
NJdevPro Dec 1, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .github/workflows/c-cpp.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: C/C++ CI

on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- name: make
run: make
- name: make test
run: bash test.sh
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
*~
minilisp
minilisp
*.o
17 changes: 14 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
CFLAGS=-std=gnu99 -g -O2 -Wall
CC=gcc
CFLAGS=-std=gnu99 -O2 -Wall -Wshadow -Wextra -Wno-unused-parameter
LDFLAGS=

.PHONY: clean test

minilisp: minilisp.c
all: bestline.o minilisp

bestline.o:
cd bestline && $(MAKE)

minilisp: bestline.o
cd src && $(CC) $(CFLAGS) -c gc.c minilisp.c repl.c
cd src && $(CC) $(LDFLAGS) -o minilisp ../bestline/bestline.o gc.o minilisp.o repl.o
mv src/minilisp .

clean:
rm -f minilisp *~
cd bestline && $(MAKE) clean
cd src && rm -f minilisp *~

test: minilisp
@./test.sh
178 changes: 160 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,102 @@
MiniLisp
========
MiniLisp with REPL
==================

Foreword by N. Janin:
This is my attempt at making Rui Ueyama (rui314)'s MiniLisp slightly more user friendly
and powerful.
Not being limited by the 1000 lines challenge, I've added a number of basic primitives
to the original program, while trying to keep the goal of simplicity and conciseness.

The whole program compiles to less than 100 kb without debugging symbols and should be
able to run on low powered devices.

The added primitives:
* strings and conversion
* predicates >, >=, <=, not,
* functions list, atom, length, reverse, progn, load.

This has the side effect of being much faster as well, since all these primitives are compiled instead of being interpreted.

Among the bells and whistles, I've added a Read-Eval-Print-Loop (REPL) based on Justine Tunney (jart)'s bestline.

In this version, instead of passing a file using pipes, you simply pass the files as command parameters :
./minilisp f1 f2 etc

The files all share the same environment, so all the symbols, functions and macros defined
in f1 can be reused in the following files. The REPL is summonned after execution, unless we pass the option
-r to the command line, in which case the interpreted quits immediately at the end.

You can also pass a simple Lisp command as parameter:
./minilisp -x "(+ 1 1)"

The Lisp command will be evaluated and then the REPL is summonned.
However we can quit immediately after execution with -r (or --no-repl).

## REPL Shortcuts

```
CTRL-Enter CONTINUE ON NEXT LINE
CTRL-E END
CTRL-A START
CTRL-B BACK
CTRL-F FORWARD
CTRL-L CLEAR
CTRL-H BACKSPACE
CTRL-D DELETE
CTRL-Y YANK
CTRL-D EOF (IF EMPTY)
CTRL-N NEXT HISTORY
CTRL-P PREVIOUS HISTORY
CTRL-R SEARCH HISTORY
CTRL-G CANCEL SEARCH
ALT-< BEGINNING OF HISTORY
ALT-> END OF HISTORY
ALT-F FORWARD WORD
ALT-B BACKWARD WORD
CTRL-ALT-F FORWARD EXPR
CTRL-ALT-B BACKWARD EXPR
ALT-RIGHT FORWARD EXPR
ALT-LEFT BACKWARD EXPR
CTRL-K KILL LINE FORWARDS
CTRL-U KILL LINE BACKWARDS
ALT-H KILL WORD BACKWARDS
CTRL-W KILL WORD BACKWARDS
CTRL-ALT-H KILL WORD BACKWARDS
ALT-D KILL WORD FORWARDS
ALT-Y ROTATE KILL RING AND YANK AGAIN
ALT-\ SQUEEZE ADJACENT WHITESPACE
CTRL-T TRANSPOSE
ALT-T TRANSPOSE WORD
ALT-U UPPERCASE WORD
ALT-L LOWERCASE WORD
ALT-C CAPITALIZE WORD
CTRL-C INTERRUPT PROCESS
CTRL-Z SUSPEND PROCESS
CTRL-\ QUIT PROCESS
CTRL-S PAUSE OUTPUT
CTRL-Q UNPAUSE OUTPUT (IF PAUSED)
CTRL-Q ESCAPED INSERT
CTRL-SPACE SET MARK
CTRL-X CTRL-X GOTO MARK
CTRL-Z SUSPEND PROCESS
```

The REPL also saves the history of commands in the file history.txt
This file is loaded at startup, so one can recall previous commands.

Known bugs:
* recall of multiline commands does not work as expected.
* this doesn't have tail call optimization, so expect crashes with sometimes with surprisingly short lists.

Original README (completed)
===============

One day I wanted to see what I can do with 1k lines of C and
decided to write a Lisp interpreter. That turned to be a
fun weekend project, and the outcome is a mini lisp implementation
that supports

- integers, symbols, cons cells,
- integers, symbols, cons cells
- global variables,
- lexically-scoped local variables,
- closures,
Expand Down Expand Up @@ -86,6 +176,16 @@ car.
(setcar cell 'x)
cell ; -> (x . b)

`length` and `reverse` operate either on their arguments, or a single list or a string.

(length '(1 2 3)) ; -> 3
(length 1 2 t) ; -> 3
(length "1 2 3") ; -> 5

(reverse '(a b c)) ; -> (c b a)
(reverse "1234") ; -> "4321"
(reverse '((a) b "c")) ; -> (c b (a))

### Numeric operators

`+` returns the sum of the arguments.
Expand Down Expand Up @@ -116,6 +216,8 @@ the second.
(< 3 3) ; -> ()
(< 4 3) ; -> ()

The other numerical predicates `>`, `<=`, `>=` work in a similar fashion.

### Conditionals

`(if cond then else)` is the only conditional in the language. It first
Expand All @@ -132,18 +234,52 @@ loop by tail recursion in MiniLisp. The answer is no. Tail calls consume stack
space in MiniLisp, so a loop written as recursion will fail with the memory
exhaustion error.

### Imperative programming

`(progn expr expr ...)` executes several expressions in sequence.

( progn (print "I own ")
(defun add(x y)(+ x y))
(print (add 3 7)
(println " cents") ) ; -> prints "I own 10 cents"

### Equivalence test operators

`eq` takes two arguments and returns `t` if the objects are the same. What `eq`
really does is a pointer comparison, so two objects happened to have the same
contents but actually different are considered to not be the same by `eq`.
`eq` can also compare two strings.

### String functions

`eq` can also compare two strings.

(eq "Hello" "Hello") ; -> t
(eq "Hello" "hello") ; -> ()

`string-concat` concatenates strings.

(string-concat) ; -> ""
(string-concat "A" "B" "C" "D") ; -> "ABCD"

`symbol->string` turns a symbol into a string.

(define sym 'hello) ; -> hello
(symbol->string sym) ; -> "hello"

`string->symbol` turns a string into a symbol of the same name.

(string->symbol "hello") ; -> hello

### Output operators

`println` prints a given object to the standard output.
`print` prints a given object to the standard output.

(print 3) ; -> "3"
(print '(hello world)) ; -> "(hello world)"
(print "hello" "world") ; -> "hello world"

(println 3) ; prints "3"
(println '(hello world)) ; prints "(hello world)"
`println` does the same, adding a return at the end.

### Definitions

Expand Down Expand Up @@ -200,6 +336,24 @@ is not defined.
(define val (+ 3 5))
(setq val (+ val 1)) ; increment "val"

### Introspection

`atom` returns () if the argument is a cell, t otherwise.

(atom '(a b)) ; -> ()
(atom "") ; -> t
(atom ()) ; -> t

### System functions
`load` loads a Lisp file and evaluates all its content, adding it to the environment.

(load "example/nqueens.lisp") -> run the file and store its evaluated functions
and macros

`exit` quits the interpreter and returns the integer passed as parameter.

(exit 0) -> quit with success

### Macros

Macros look similar to functions, but they are different that macros take an
Expand Down Expand Up @@ -232,15 +386,3 @@ than itself. Useful for writing a macro that introduces new identifiers.

As in the traditional Lisp syntax, `;` (semicolon) starts a single line comment.
The comment continues to the end of line.

No GC Branch
------------

There is a MiniLisp branch from which the code for garbage collection has been
stripped. The accepted language is the same, but the code is simpler than the
master branch's one. The reader might want to read the nogc branch first, then
proceed to the master branch, to understand the code step by step.

The nogc branch is available at
[nogc](https://github.com/rui314/minilisp/tree/nogc). The original is available
at [master](https://github.com/rui314/minilisp).
9 changes: 9 additions & 0 deletions bestline/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
*.o
ape.lds
history.txt
cosmopolitan.h
cosmopolitan.a
bestline_example
bestline_example.com
bestline_example.com.dbg
bestline_multi
30 changes: 30 additions & 0 deletions bestline/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
Bestline is released under the 2-clause BSD license.

Copyright (c) 2018-2021 Justine Tunney <[email protected]>
Copyright (c) 2010-2016 Salvatore Sanfilippo <[email protected]>
Copyright (c) 2010-2013 Pieter Noordhuis <[email protected]>

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45 changes: 45 additions & 0 deletions bestline/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
all: bestline_example bestline_multi

bestline_example: bestline.o example.o
$(CC) $(LDFLAGS) bestline.o example.o -o $@

bestline_multi: bestline.o multi.o
$(CC) $(LDFLAGS) bestline.o multi.o -o $@

bestline.o: bestline.c bestline.h Makefile
example.o: example.c bestline.h Makefile
multi.o: multi.c bestline.h Makefile

libbestline.so: bestline.c
$(CC) $(LDFLAGS) -fPIC -shared bestline.c -o $@

clean:
rm -f bestline_example bestline.o example.o bestline_example.com bestline_example.com.dbg multi.o bestline_multi libbestline.so

################################################################################
# compile on linux the demo as a binary that runs on seven operating systems

bestline_example.com: bestline_example.com.dbg
objcopy -S -O binary $< $@
bestline_example.com.dbg: bestline.c example.c crt.o ape.o ape.lds cosmopolitan.a cosmopolitan.h
gcc -g -Os -static -fno-pie -no-pie -mno-red-zone -nostdlib -nostdinc -fno-omit-frame-pointer -pg -mnop-mcount -o $@ bestline.c example.c -Wl,--gc-sections -fuse-ld=bfd -Wl,-T,ape.lds -include cosmopolitan.h crt.o ape.o cosmopolitan.a
bestline_multi.com: bestline_multi.com.dbg
objcopy -S -O binary $< $@
bestline_multi.com.dbg: bestline.c multi.c crt.o ape.o ape.lds cosmopolitan.a cosmopolitan.h
gcc -g -Os -static -fno-pie -no-pie -mno-red-zone -nostdlib -nostdinc -fno-omit-frame-pointer -pg -mnop-mcount -o $@ bestline.c example.c -Wl,--gc-sections -fuse-ld=bfd -Wl,-T,ape.lds -include cosmopolitan.h crt.o ape.o cosmopolitan.a
crt.o:; wget --compression=gzip https://justine.lol/cosmopolitan/crt.o
ape.o:; wget --compression=gzip https://justine.lol/cosmopolitan/ape.o
ape.lds:; wget --compression=gzip https://justine.lol/cosmopolitan/ape.lds
cosmopolitan.h:; wget --compression=gzip https://justine.lol/cosmopolitan/cosmopolitan.h
cosmopolitan.a:; wget --compression=gzip https://justine.lol/cosmopolitan/cosmopolitan.a

################################################################################
# make sure it compiles in weird environments

check:
gcc -c -Wall -Wextra -O3 -o /tmp/bestline.o bestline.c
g++ -xc++ -c -Wall -Wextra -O3 -o /tmp/bestline.o bestline.c
gcc -pedantic -std=c99 -c -Wall -Wextra -O3 -o /tmp/bestline.o bestline.c
clang -c -Wall -Wextra -Wall -Wextra -O3 -o /tmp/bestline.o bestline.c
clang++ -xc++ -c -Wall -Wextra -Wall -Wextra -O3 -o /tmp/bestline.o bestline.c
clang -pedantic -std=c99 -c -Wall -Wextra -O3 -o /tmp/bestline.o bestline.c
Loading