You are on page 1of 56

Build

Your Own Lisp

S-

Q-

10

11

12

13

14

15

16

17

Build Your Own Lisp


C 1000
Lisp

Lisp
C
C

(Author)Daniel Holden
(contact@theorangeduck.com)
http://buildyourownlisp.com/
BuildYourOwnLisp
CC BY-NC-SA 3.0

(Translator)KSCO (numbksco@gmail.com)
https://ksco.gitbooks.io/build-your-own-lisp/
BuildYourOwnLispCn
CC BY-NC-SA 3.0

Build Your Own Lisp

C
C Linux C
Apple OS X Microsoft Windows C C
C
C C

C UnixLinux C

Build Your Own Lisp

C
C
C
C
C

17
Lisp

Lisp
Build Your Own Lisp

Build Your Own Lisp

Linux gedit
IDE IDE

Mac OS X TextWrangler
Xcode IDE
Microsoft Windows Notepad++
Visual Studio C

Linux C
Ubuntu Debian sudo apt-get install buildessential

Mac OS X Xcode
xcode-select --install Command Line Tools
Microsoft Windows MinGW

Build Your Own Lisp

C
cc --version

Mac

$ cc --version
Apple LLVM version 7.0.0 (clang-700.1.76)
Target: x86_64-apple-darwin15.0.0
Thread model: posix

Hello World

hello_world.c C

#include <stdio.h>
int main(int argc, char** argv) {
puts("Hello, world!");
return 0;
}

stdio.h

main int argc


char** argv int C main

main puts ( stdio.h )


"Hello, world!" Hello, world! puts
put string return 0; main
0 0

hello_world.c

Build Your Own Lisp

cc -std=c99 -Wall hello_world.c -o hello_world

hello_world.c
hello_world -std=c99 C

hello_world.c hello_world
./hello_world
Hello, world!
C

C C

hello_world.c

Build Your Own Lisp

#include <stdio.h>
int main(int argc, char** argv) {
puts("Hello, world!");
return 0;
}

"Hello, world!"
main
puts

Build Your Own Lisp


C (feature)C
C
C
C
C

C
()

main main

C
C

= C
;
count ( int )
int count;

count
int count = 10;

10

Build Your Own Lisp

void

char

char last_initial = 'H';

int

int age = 32;

long

long age_of_universe = 13798000000;

float

float liters_per_pint = 0.568f;

double

double speed_of_swallow = 0.01072896;

,
{} ; return

int x y
int add_together(int x, int y) {
int result = x + y;
return result;
}

added
int added = add_together(10, 18);

point float x y
struct typedef

11

Build Your Own Lisp

typedef struct {
float x;
float y;
} point;

point p;
p.x = 0.1;
p.y = 10.0;
float length = sqrt(p.x * p.x + p.y * p.y);

* int*
int main char**

char
C C

C char* ( char )
C

"
"Hello, world!" char*

12

Build Your Own Lisp

if
if else

( || )( && )
0

x 10 100
if (x > 10 && x < 100) {
puts("x is greater than 10 and less than 100!");
} else {
puts("x is less than 11 or greater than 99!");
}

C while while
while

int i = 10;
while (i > 0) {
puts("Loop Iteration");
i = i - 1;
}

for while for ;

for while
0 9 1 10
for (int i = 0; i < 10; i++) {
puts("Loop Iteration");
}

13

Build Your Own Lisp

for 5 "Hello, world!"


while 5 "Hello, world!"
Hello n "Hello world!" main

> <
+ -
+=
do...while
switch
break
continue
typedef

14

Build Your Own Lisp


--
Lisp

REPL read-evaluate-print loop (--)


Python
REPL

Lisp

stdio.h fgets

printf

15

Build Your Own Lisp

#include <stdio.h>
/* Declare a buffer for user input of size 2048 */
static char input[2048];
int main(int argc, char** argv) {
/* Print Version and Exit Information */
puts("Lispy Version 0.0.0.0.1");
puts("Press Ctrl+c to Exit\n");
/* In a never ending loop */
while (1) {
/* Output our prompt */
fputs("lispy> ", stdout);
/* Read a line of user input of maximum size 2048 */
fgets(input, 2048, stdin);
/* Echo input back to user */
printf("No you're a %s", input);
}
return 0;
}

/*...*/
C

static char input[2048]; 2048

static [2048]
while(1) 1

fputs puts fputs


fgets
stdin stdout
<stdio.h> stdin

16

Build Your Own Lisp

fgets
input
2048
printf printf

%s printf %s s
( string )
printf
fgets printf
C

cc -std=c99 -Wall prompt.c -o prompt

Ctrl+c

Lispy Version 0.0.0.0.1


Press Ctrl+c to Exit
lispy> hello
No You're a hello
lispy> my name is Dan
No You're a my name is Dan
lispy> Stop being so rude!
No You're a Stop being so rude!
lispy>

Mac Linux

17

Build Your Own Lisp

Lispy Version 0.0.0.0.3


Press Ctrl+c to Exit
lispy> hel^[[D^[[C

^[[D ^[[C

Windows
Mac Linux editline fputs fgets

Windows
editline

editline
editline readline add_history readline
fgets add_history

18

Build Your Own Lisp

#include <stdio.h>
#include <stdlib.h>
#include <editline/readline.h>
#include <editline/history.h>
int main(int argc, char** argv) {
/* Print Version and Exit Information */
puts("Lispy Version 0.0.0.0.1");
puts("Press Ctrl+c to Exit\n");
/* In a never ending loop */
while (1) {
/* Output our prompt and get input */
char* input = readline("lispy> ");
/* Add input to history */
add_history(input);
/* Echo input back to user */
printf("No you're a %s\n", input);
/* Free retrieved input */
free(input);
}
return 0;
}

<stdlib.h> free <editline/readline.h>


<editline/history.h> editline readline add_history

readline add_history
printf
fgets readline printf
free readline
input readline fgets

editline

19

Build Your Own Lisp

editline
fatal error: editline/readline.h: No such file or directory #include
<editline/readline.h>

Mac editline Command Line Tools


#include
<editline/history.h>

Linux sudo apt-get install libedit-dev editline Fedora


su -c "yum install libedit-dev*"
editline
undefined reference to `readline'
undefined reference to `add_history'

editline -ledit

cc -std=c99 -Wall prompt.c -ledit -o prompt

editline

C
(portability)
C (preprocessor)

#
(include)

20

Build Your Own Lisp

Windows readline add_history


editline
#ifdef #else #endif
#ifdef #else #else
endif WindowsLinux Mac

21

Build Your Own Lisp

#include <stdio.h>
#include <stdlib.h>
/* If we are compiling on Windows compile these functions */
#ifdef _WIN32
#include <string.h>
static char buffer[2048];
/* Fake readline function */
char* readline(char* prompt) {
fputs(prompt, stdout);
fgets(buffer, 2048, stdin);
char* cpy = malloc(strlen(buffer)+1);
strcpy(cpy, buffer);
cpy[strlen(cpy)-1] = '\0';
return cpy;
}
/* Fake add_history function */
void add_history(char* unused) {}
/* Otherwise include the editline headers */
#else
#include <editline/readline.h>
#include <editline/history.h>
#endif
int main(int argc, char** argv) {
puts("Lispy Version 0.0.0.0.1");
puts("Press Ctrl+c to Exit\n");
while (1) {
/* Now in either case readline will be correctly defined */
char* input = readline("lispy> ");
add_history(input);
printf("No you're a %s\n", input);
free(input);
}
return 0;
}

prompt_unix.c

22

Build Your Own Lisp

#include <stdio.h>
#include <stdlib.h>
#include <editline/readline.h>
#include <editline/history.h>
int main(int argc, char** argv) {
/* Print Version and Exit Information */
puts("Lispy Version 0.0.0.0.1");
puts("Press Ctrl+c to Exit\n");
/* In a never ending loop */
while (1) {
/* Output our prompt and get input */
char* input = readline("lispy> ");
/* Add input to history */
add_history(input);
/* Echo input back to user */
printf("No you're a %s\n", input);
/* Free retrived input */
free(input);
}
return 0;
}

prompt_windows.c

23

Build Your Own Lisp

#include <stdio.h>
/* Declare a buffer for user input of size 2048 */
static char input[2048];
int main(int argc, char** argv) {
/* Print Version and Exit Information */
puts("Lispy Version 0.0.0.0.1");
puts("Press Ctrl+c to Exit\n");
/* In a never ending loop */
while (1) {
/* Output our prompt */
fputs("lispy> ", stdout);
/* Read a line of user input of maximum size 2048 */
fgets(input, 2048, stdin);
/* Echo input back to user */
printf("No you're a %s", input);
}
return 0;
}

prompt.c

24

Build Your Own Lisp

#include <stdio.h>
#include <stdlib.h>
/* If we are compiling on Windows compile these functions */
#ifdef _WIN32
#include <string.h>
static char buffer[2048];
/* Fake readline function */
char* readline(char* prompt) {
fputs(prompt, stdout);
fgets(buffer, 2048, stdin);
char* cpy = malloc(strlen(buffer)+1);
strcpy(cpy, buffer);
cpy[strlen(cpy)-1] = '\0';
return cpy;
}
/* Fake add_history function */
void add_history(char* unused) {}
/* Otherwise include the editline headers */
#else
#include <editline/readline.h>
#include <editline/history.h>
#endif
int main(int argc, char** argv) {
puts("Lispy Version 0.0.0.0.1");
puts("Press Ctrl+c to Exit\n");
while (1) {
/* Now in either case readline will be correctly defined */
char* input = readline("lispy> ");
add_history(input);
printf("No you're a %s\n", input);
free(input);
}
return 0;
}

25

Build Your Own Lisp

lispy>

\n
printf

printf
#ifndef
#define
_WIN32 Windows Linux Mac

26

Build Your Own Lisp

19 50 Noam Chomsky

> The cat walked on the carpet.


cat and
> The cat and dog walked on the carpet.
cat and

> The cat and mouse and dog walked on the carpet.
> The white cat and black dog walked on the carpet.

C if
if

> if (x > 5) { return x; }


> if (x > 5) { if (x > 10) { return x; } }
Chomsky

(grammar)

27

Build Your Own Lisp

"""" (
)

( Lisp )

mpc

mpc ()(Parser Combinators)

( Doge ) mpc
Doge
( Adjective ) wow many so such
( Noun ) lisp language c book build
( Phrase ) ( Adjective ) ( Noun )
Doge 0 ( Phrase )

mpc_parser_t*
Adjective Noun mpc_or
mpc_sym

28

Build Your Own Lisp

/* Build a parser 'Adjective' to recognize descriptions */


mpc_parser_t* Adjective = mpc_or(4,
mpc_sym("wow"), mpc_sym("many"),
mpc_sym("so"), mpc_sym("such")
);
/* Build a parser 'Noun' to recognize things */
mpc_parser_t* Noun = mpc_or(5,
mpc_sym("lisp"), mpc_sym("language"),
mpc_sym("book"),mpc_sym("build"),
mpc_sym("c")
);

mpc

mpc Lisp
Adjective Noun ( Phrase )
mpc_and
Adjective Noun
mpcf_strfold free
mpc_parser_t* Phrase = mpc_and(2, mpcf_strfold, Adjective, Noun, free);

Doge 0 (Phrase) mpc_many


mpcf_strfold
mpc_parser_t* Doge = mpc_many(mpcf_strfold, Phrase);

Doge Doge
Doge
"wow book such language many lisp"
"so c such build such language"
"many build wow c"
""
"wow lisp wow c many language"
"so c"

mpc

mpc

29

Build Your Own Lisp

mpc

C
mpcf_strfold free

Doge
mpc_parser_t* Adjective = mpc_new("adjective");
mpc_parser_t* Noun = mpc_new("noun");
mpc_parser_t* Phrase = mpc_new("phrase");
mpc_parser_t* Doge = mpc_new("doge");
mpca_lang(MPCA_LANG_DEFAULT,
" \
adjective : \"wow\" | \"many\" \
| \"so\" | \"such\"; \
noun : \"lisp\" | \"language\" \
| \"book\" | \"build\" | \"c\"; \
phrase : <adjective> <noun>; \
doge : <phrase>*; \
",
Adjective, Noun, Phrase, Doge);
/* Do some parsing here... */
mpc_cleanup(4, Adjective, Noun, Phrase, Doge);

1. mpc_new
2. mpca_lang
mpca_lang C

: ;

30

Build Your Own Lisp

"ab"

ab

'a'

'a' 'b'

a b

'a''b'

a b

'a'*

0 a

'a'+

1 a

<abba>

abba

mpca_lang
mpc_many mpc_and mpc_or

doge_code.c

31

Build Your Own Lisp

#include "mpc.h"
int main(int argc, char** argv) {
/* Build a parser 'Adjective' to recognize descriptions */
mpc_parser_t* Adjective = mpc_or(4,
mpc_sym("wow"), mpc_sym("many"),
mpc_sym("so"), mpc_sym("such")
);
/* Build a parser 'Noun' to recognize things */
mpc_parser_t* Noun = mpc_or(5,
mpc_sym("lisp"), mpc_sym("language"),
mpc_sym("book"), mpc_sym("build"),
mpc_sym("c")
);
mpc_parser_t* Phrase = mpc_and(2, mpcf_strfold,
Adjective, Noun, free);
mpc_parser_t* Doge = mpc_many(mpcf_strfold, Phrase);
/* Do some parsing here... */
mpc_delete(Doge);
return 0;
}

doge_grammar.c

32

Build Your Own Lisp

#include "mpc.h"
int main(int argc, char** argv) {
mpc_parser_t* Adjective = mpc_new("adjective");
mpc_parser_t* Noun = mpc_new("noun");
mpc_parser_t* Phrase = mpc_new("phrase");
mpc_parser_t* Doge = mpc_new("doge");
mpca_lang(MPCA_LANG_DEFAULT,
" \
adjective : \"wow\" | \"many\" \
| \"so\" | \"such\"; \
noun : \"lisp\" | \"language\" \
| \"book\" | \"build\" | \"c\"; \
phrase : <adjective> <noun>; \
doge : <phrase>*; \
",
Adjective, Noun, Phrase, Doge);
/* Do some parsing here... */
mpc_cleanup(4, Adjective, Noun, Phrase, Doge);
return 0;
}

Doge
" \
\
0.01 52.221
https://github.com/ksco URL
the cat sat on the mat
| * +
JSON

33

Build Your Own Lisp

mpc
Lisp

1 + 2 + 6

+ 1 2 6

6 + (2 * 9)

+ 6 (* 2 9)

(10 * 2) / (4 + 2)

/ (* 10 2) (+ 4 2)

( Program )( Operator )
( Expression ) ( Expression )
( Operator )( Expression )

( Program )

--> --> (Expression) -->

(Expression)

( --> --> )

(Operator)

'+''-''*' '/'

( Number )

- --> 0 9

34

Build Your Own Lisp

(Regular Expression)

[abcdef]

abcdef

[a-f]

a f

a?

a a

a*

0 a

a+

1 a

mpc / Number /-?[0-9]+/

mpc
Linux Mac editline
mpc mpc
parsing.c mpc
mpc.h mpc.c parsing.c
parsing.c #include "mpc.h" mpc mpc.c
Linux -lm
Mac Linux
cc -std=c99 -Wall parsing.c mpc.c -ledit -lm -o parsing

Windows
cc -std=c99 -Wall parsing.c mpc.c -o parsing

#include <mpc.h>

35

Build Your Own Lisp

C <> ""
stdio.h
mpc.h

/* Create Some Parsers */


mpc_parser_t* Number = mpc_new("number");
mpc_parser_t* Operator = mpc_new("operator");
mpc_parser_t* Expr = mpc_new("expr");
mpc_parser_t* Lispy = mpc_new("lispy");
/* Define them with the following Language */
mpca_lang(MPCA_LANG_DEFAULT,
" \
number : /-?[0-9]+/ ; \
operator : '+' | '-' | '*' | '/' ; \
expr : <number> | '(' <operator> <expr>+ ')' ; \
lispy : /^/ <operator> <expr>+ /$/ ; \
",
Number, Operator, Expr, Lispy);

main
main
return
/ Undefine and Delete our Parsers / mpc_cleanup(4, Number, Operator, Expr, Lispy);
undefined reference to 'mpc_lang'
mpca_lang mpc a

mpc
while
printf

36

Build Your Own Lisp

/* Attempt to Parse the user Input */


mpc_result_t r;
if (mpc_parse("<stdin>", input, Lispy, &r)) {
/* On Success Print the AST */
mpc_ast_print(r.output);
mpc_ast_delete(r.output);
} else {
/* Otherwise Print the Error */
mpc_err_print(r.error);
mpc_err_delete(r.error);
}

mpc_parse Lispy input


&r 1 0 r
&
r output
mpc_ast_print mpc_ast_delete

r error mpc_err_print
mpc_err_delete

Lispy Version 0.0.0.0.2


Press Ctrl+c to Exit
lispy> + 5 (* 2 2)
>
regex
operator|char:1:1 '+'
expr|number|regex:1:3 '5'
expr|>
char:1:5 '('
operator|char:1:6 '*'
expr|number|regex:1:8 '2'
expr|number|regex:1:10 '2'
char:1:11 ')'
regex
lispy> hello
<stdin>:1:1: error: expected whitespace, '+', '-', '*' or '/' at 'h'
lispy> / 1dog

<stdin>:1:4: error: expected one of '0123456789', whitespace, '-', one or more of one of '0123456789'
lispy>

<stdin>:1:1: error: Parser Undefined!


mpca_lang

37

Build Your Own Lisp

parsing.c

#include "mpc.h"
#ifdef _WIN32
static char buffer[2048];
char* readline(char* prompt) {
fputs(prompt, stdout);
fgets(buffer, 2048, stdin);
char* cpy = malloc(strlen(buffer)+1);
strcpy(cpy, buffer);
cpy[strlen(cpy)-1] = '\0';
return cpy;
}
void add_history(char* unused) {}
#else
#include <editline/readline.h>
#include <editline/history.h>
#endif
int main(int argc, char** argv) {
/* Create Some Parsers */
mpc_parser_t* Number = mpc_new("number");
mpc_parser_t* Operator = mpc_new("operator");
mpc_parser_t* Expr = mpc_new("expr");
mpc_parser_t* Lispy = mpc_new("lispy");
/* Define them with the following Language */
mpca_lang(MPCA_LANG_DEFAULT,
" \
number : /-?[0-9]+/ ; \
operator : '+' | '-' | '*' | '/' ; \
expr : <number> | '(' <operator> <expr>+ ')' ; \
lispy : /^/ <operator> <expr>+ /$/ ; \
",
Number, Operator, Expr, Lispy);
puts("Lispy Version 0.0.0.0.2");
puts("Press Ctrl+c to Exit\n");
while (1) {
char* input = readline("lispy> ");
add_history(input);

38

Build Your Own Lisp

/* Attempt to parse the user input */


mpc_result_t r;
if (mpc_parse("<stdin>", input, Lispy, &r)) {
/* On success print and delete the AST */
mpc_ast_print(r.output);
mpc_ast_delete(r.output);
} else {
/* Otherwise print and delete the Error */
mpc_err_print(r.error);
mpc_err_delete(r.error);
}
free(input);
}
/* Undefine and delete our parsers */
mpc_cleanup(4, Number, Operator, Expr, Lispy);
return 0;
}

a b :
aababa bbaa

a b
: ababab aba
%

add sub mul div


0.01 5.21 10.2

39

Build Your Own Lisp

(Abstract Syntax Tree


AST)

mpc.h
mpc_ast_t

typedef struct mpc_ast_t {


char* tag;
char* contents;
mpc_state_t state;
int children_num;
struct mpc_ast_t** children;
} mpc_ast_t;

tag tag
expr|number|regex
tag

contents '*' '(' '5'

state

children_num children

children mpc_ast_t**

40

Build Your Own Lisp

children [x]
children[0] C 0
mpc_ast_t*
-> .
/* Load AST from output */
mpc_ast_t* a = r.output;
printf("Tag: %s\n", a->tag);
printf("Contents: %s\n", a->contents);
printf("Number of children: %i\n", a->children_num);
/* Get First Child */
mpc_ast_t* c0 = a->children[0];
printf("First Child Tag: %s\n", c0->tag);
printf("First Child Contents: %s\n", c0->contents);
printf("First Child Number of children: %i\n",
c0->children_num);

(Recursion)

1
1
C

41

Build Your Own Lisp

int number_of_nodes(mpc_ast_t* t) {
if (t->children_num == 0) { return 1; }
if (t->children_num >= 1) {
int total = 1;
for (int i = 0; i < t->children_num; i++) {
total = total + number_of_nodes(t->children[i]);
}
return total;
}
}

t->children_num == 0
t->children_num >= 1

lispy> * 10 (+ 1 51)
>
regex
operator|char:1:1 '*'
expr|number|regex:1:3 '10'
expr|>
char:1:6 '('
operator|char:1:7 '+'
expr|number|regex:1:9 '1'
expr|number|regex:1:11 '51'
char:1:13 ')'
regex

number

42

Build Your Own Lisp

expr number
( ( )
)
number_of_nodes
C long ()
tag
contents

atoi

char* long

strcmp

char* 0

strstr

char*
0

strcmp strstr tag

long eval(mpc_ast_t* t) {
/* If tagged as number return it directly. */
if (strstr(t->tag, "number")) {
return atoi(t->contents);
}
/* The operator is always second child. */
char* op = t->children[1]->contents;
/* We store the third child in `x` */
long x = eval(t->children[2]);
/* Iterate the remaining children and combining. */
int i = 3;
while (strstr(t->children[i]->tag, "expr")) {
x = eval_op(x, op, eval(t->children[i]));
i++;
}
return x;
}

eval_op

43

Build Your Own Lisp

/* Use operator string to see which operation to perform */


long eval_op(long x, char* op, long y) {
if (strcmp(op, "+") == 0) { return x + y; }
if (strcmp(op, "-") == 0) { return x - y; }
if (strcmp(op, "*") == 0) { return x * y; }
if (strcmp(op, "/") == 0) { return x / y; }
return 0;
}

long result = eval(r.output);


printf("%li\n", result);
mpc_ast_delete(r.output);

Lispy Version 0.0.0.0.3


Press Ctrl+c to Exit
lispy> + 5 6
11
lispy> - (* 10 10) (+ 1 1 1)
97

evaluation.c

#include "mpc.h"
#ifdef _WIN32
static char buffer[2048];
char* readline(char* prompt) {
fputs(prompt, stdout);
fgets(buffer, 2048, stdin);
char* cpy = malloc(strlen(buffer)+1);
strcpy(cpy, buffer);
cpy[strlen(cpy)-1] = '\0';
return cpy;

44

Build Your Own Lisp

}
void add_history(char* unused) {}
#else
#include <editline/readline.h>
#include <editline/history.h>
#endif
/* Use operator string to see which operation to perform */
long eval_op(long x, char* op, long y) {
if (strcmp(op, "+") == 0) { return x + y; }
if (strcmp(op, "-") == 0) { return x - y; }
if (strcmp(op, "*") == 0) { return x * y; }
if (strcmp(op, "/") == 0) { return x / y; }
return 0;
}
long eval(mpc_ast_t* t) {
/* If tagged as number return it directly. */
if (strstr(t->tag, "number")) {
return atoi(t->contents);
}
/* The operator is always second child. */
char* op = t->children[1]->contents;
/* We store the third child in `x` */
long x = eval(t->children[2]);
/* Iterate the remaining children and combining. */
int i = 3;
while (strstr(t->children[i]->tag, "expr")) {
x = eval_op(x, op, eval(t->children[i]));
i++;
}
return x;
}
int main(int argc, char** argv) {
mpc_parser_t* Number = mpc_new("number");
mpc_parser_t* Operator = mpc_new("operator");
mpc_parser_t* Expr = mpc_new("expr");
mpc_parser_t* Lispy = mpc_new("lispy");
mpca_lang(MPCA_LANG_DEFAULT,
" \
number : /-?[0-9]+/ ; \
operator : '+' | '-' | '*' | '/' ; \
expr : <number> | '(' <operator> <expr>+ ')' ; \

45

Build Your Own Lisp

lispy : /^/ <operator> <expr>+ /$/ ; \


",
Number, Operator, Expr, Lispy);
puts("Lispy Version 0.0.0.0.3");
puts("Press Ctrl+c to Exit\n");
while (1) {
char* input = readline("lispy> ");
add_history(input);
mpc_result_t r;
if (mpc_parse("<stdin>", input, Lispy, &r)) {
long result = eval(r.output);
printf("%li\n", result);
mpc_ast_delete(r.output);
} else {
mpc_err_print(r.error);
mpc_err_delete(r.error);
}
free(input);
}
mpc_cleanup(4, Number, Operator, Expr, Lispy);
return 0;
}

strstr expr ( tag )


strcmp ( )
% % 10 6 4
^ ^ 4 2 16
min min 1 5 3 1
max max 1 5 3 5
-

46

Build Your Own Lisp

Lispy Version 0.0.0.0.3


Press Ctrl+c to Exit
lispy> / 10 0

47

Build Your Own Lisp

S-

48

Build Your Own Lisp

Q-

49

Build Your Own Lisp

50

Build Your Own Lisp

51

Build Your Own Lisp

52

Build Your Own Lisp

53

Build Your Own Lisp

54

Build Your Own Lisp

55

Build Your Own Lisp

56

You might also like