Skip to content

Commit 4aa868a

Browse files
committed
Add command line arguments parsing
Fixed tests
1 parent a5313aa commit 4aa868a

5 files changed

Lines changed: 225 additions & 91 deletions

File tree

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
*~
2-
minilisp
2+
minilisp
3+
*.o

README.md

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,29 @@ MiniLisp with REPL
22
==================
33

44
Foreword by N. Janin:
5-
This is my attempt at making Rui Ueyama (rui314)'s MiniLisp slightly more user friendly and powerful.
6-
Not being limited by the 1000 lines challenge, I've added a few basic primitives
5+
This is my attempt at making Rui Ueyama (rui314)'s MiniLisp slightly more user friendly
6+
and powerful.
7+
Not being limited by the 1000 lines challenge, I've added a number of basic primitives
78
to the original program, while trying to keep the goal of simplicity and conciseness.
9+
The whole program compiles to less than 100 kb without debugging symbols and should be
10+
able to run on low powered devices.
11+
812
The whole program compiles to less than 100 kb and should be able to run on low powered devices.
913
The added primitives:
10-
* operators >, >=, <=, or, and, not,
14+
* strings
15+
* predicates >, >=, <=, or, and, not,
1116
* functions length, reverse, progn, load.
12-
This has the side effect of being much faster as well, since all these primitives are compiled
13-
instead of being interpreted.
17+
18+
This has the side effect of being much faster as well, since all these primitives are
19+
compiled instead of being interpreted.
1420

1521
Among the bells and whistles, I've added a REPL based on Justine Tunney (jart)'s bestline.
1622

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

20-
The files all share the same environment, so all the symbols, functions and macros defined in f1 can be reused in the following files.
26+
The files all share the same environment, so all the symbols, functions and macros defined
27+
in f1 can be reused in the following files.
2128

2229
## Shortcuts
2330

@@ -93,7 +100,6 @@ Known bugs:
93100

94101

95102
Original README (completed)
96-
>>>>>>> master
97103
---------------
98104

99105
One day I wanted to see what I can do with 1k lines of C and
@@ -181,8 +187,8 @@ car.
181187
(setcar cell 'x)
182188
cell ; -> (x . b)
183189

184-
`length` and `reverse` operate on a whole list or a on string.
185-
They can also operate on their arguments when their number is > 1.
190+
`length` and `reverse` operate on a whole list or a string. They can also operate on their
191+
arguments when their number is > 1.
186192

187193
(length '(1 2 3)) ; -> 3
188194
(length 1 2 t) ; -> 3
@@ -222,7 +228,7 @@ the second.
222228
(< 3 3) ; -> ()
223229
(< 4 3) ; -> ()
224230

225-
The other comparison operators `>`, `<=`, `>=` work in a similar fashion.
231+
The other numerical predicates `>`, `<=`, `>=` work in a similar fashion.
226232

227233
`and` takes two or more arguments, evaluates them, and returns the last argument
228234
that returns true, if all the arguments return true, or () otherwise.
@@ -239,10 +245,10 @@ that returns true.
239245
(or () ()) ; -> ()
240246
(or) ; -> ()
241247

242-
NB: because all the arguments are evaluated, `and` and `or` do not operate like
243-
their counterparts written in Lisp, as those stop evaluation at the first argument
244-
that returns. If the arguments have side effects, this may affect the program
245-
differently.
248+
Nota Bene: because all the arguments are evaluated, `and` and `or` do not operate
249+
like their counterparts written in Lisp, as those stop evaluation at the first
250+
argument that returns. If the arguments have side effects, this may affect the
251+
program differently.
246252

247253
### Conditionals
248254

@@ -262,12 +268,11 @@ exhaustion error.
262268

263269
### Imperative programming
264270

265-
`progn` executes several expressions consecutively.
271+
`(progn expr expr ...)` executes several expressions in sequence.
266272

267-
(progn (print 'I 'own)
268-
(defun add(x y)(+ x y)
269-
(println (add 3 7) 'cents))) ; -> I own
270-
10 cents
273+
(progn (print "I own ")
274+
(defun add(x y)(+ x y))
275+
(println (add 3 7) " cents")) ; -> prints "I own 10 cents"
271276

272277
### Equivalence test operators
273278

@@ -284,7 +289,7 @@ contents but actually different are considered to not be the same by `eq`.
284289

285290
`string-concat` concatenates strings.
286291

287-
(string-concat) ; -> ""
292+
(string-concat) ; -> ""
288293
(string-concat "A" "B" "C" "D") ; -> "ABCD"
289294

290295
`symbol->string` turns a symbol into a string.
@@ -300,8 +305,9 @@ contents but actually different are considered to not be the same by `eq`.
300305

301306
`print` prints a given object to the standard output.
302307

303-
(print 3) ; prints "3"
304-
(print '(hello world)) ; prints "(hello world)"
308+
(print 3) ; -> "3"
309+
(print '(hello world)) ; -> "(hello world)"
310+
(print "hello" "world") ; -> "hello world"
305311

306312
`println` does the same, adding a return at the end.
307313

@@ -371,9 +377,10 @@ is not defined.
371377
### System functions
372378
`load` loads a Lisp file and evaluates all its content, adding it to the environment.
373379

374-
(load 'example/nqueens.lisp) -> run the file and store its evaluated functions and macros
380+
(load "example/nqueens.lisp") -> run the file and store its evaluated functions
381+
and macros
375382

376-
`exit` quits the interpreter and returns integer passed as parameter.
383+
`exit` quits the interpreter and returns the integer passed as parameter.
377384

378385
(exit 0) -> quit with success
379386

src/minilisp.c

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -303,15 +303,13 @@ static void print(Obj *obj) {
303303
case TNIL : fputs("()", stdout);
304304
break;
305305
case TSTRING:
306-
fputc('"', stdout);
307306
for (char *p = obj->name; *p; p++) {
308307
if (*p == '"') fputs("\\\"", stdout);
309308
else if (*p == '\n') fputc('\n', stdout);
310309
else if (*p == '\t') fputc('\t', stdout);
311310
else if (*p == '\r') fputc('\r', stdout);
312311
else fputc(*p, stdout);
313312
}
314-
fputc('"', stdout);
315313
break;
316314
default:
317315
error("Bug: print: Unknown tag type: %d", obj->type);
@@ -816,16 +814,16 @@ static Obj *prim_macroexpand(void *root, Obj **env, Obj **list) {
816814
return macroexpand(root, env, body);
817815
}
818816

819-
// (print expr)
817+
// (print ...)
820818
static Obj *prim_print(void *root, Obj **env, Obj **list) {
821-
DEFINE1(tmp);
822-
*tmp = (*list)->car;
823-
print(eval(root, env, tmp));
819+
for (Obj *args = *list; args != Nil; args = args->cdr) {
820+
print(eval(root, env, &(args->car)));
821+
}
824822
return Nil;
825823
}
826824

827825

828-
// (println expr)
826+
// (println ...)
829827
static Obj *prim_println(void *root, Obj **env, Obj **list) {
830828
prim_print(root, env, list);
831829
fputc('\n', stdout);
@@ -1012,15 +1010,24 @@ void init_minilisp(Obj **env) {
10121010

10131011
int eval_input(char *input, Obj **env, Obj **expr) {
10141012
if (setjmp(context) == 0){
1015-
*expr = read_expr(input);
1016-
if (!*expr)
1017-
return 0;
1018-
if (*expr == Cparen)
1019-
error("Stray close parenthesis");
1020-
if (*expr == Dot)
1021-
error("Stray dot");
1022-
print(eval(root, env, expr));
1023-
puts("");
1013+
Obj *result = NULL;
1014+
while (true) {
1015+
*expr = read_expr(root);
1016+
if (!*expr)
1017+
break;
1018+
1019+
if (*expr == Cparen)
1020+
error("Stray close parenthesis");
1021+
if (*expr == Dot)
1022+
error("Stray dot");
1023+
1024+
result = eval(root, env, expr);
1025+
}
1026+
1027+
if (result) {
1028+
print(result);
1029+
}
1030+
10241031
return 0;
10251032
}
10261033
else return 1;

0 commit comments

Comments
 (0)