Program Your Own Language
Program Your Own Language
S-
Q-
10
11
12
13
14
15
16
17
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
C
C Linux C
Apple OS X Microsoft Windows C C
C
C C
C UnixLinux C
C
C
C
C
C
17
Lisp
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
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
hello_world.c
hello_world.c
hello_world -std=c99 C
hello_world.c hello_world
./hello_world
Hello, world!
C
C C
hello_world.c
#include <stdio.h>
int main(int argc, char** argv) {
puts("Hello, world!");
return 0;
}
"Hello, world!"
main
puts
C (feature)C
C
C
C
C
C
()
main main
C
C
= C
;
count ( int )
int count;
count
int count = 10;
10
void
char
int
long
float
double
,
{} ; 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
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
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
0 9 1 10
for (int i = 0; i < 10; i++) {
puts("Loop Iteration");
}
13
> <
+ -
+=
do...while
switch
break
continue
typedef
14
--
Lisp
Lisp
stdio.h fgets
printf
15
#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 [2048]
while(1) 1
16
fgets
input
2048
printf printf
%s printf %s s
( string )
printf
fgets printf
C
Ctrl+c
Mac Linux
17
^[[D ^[[C
Windows
Mac Linux editline fputs fgets
Windows
editline
editline
editline readline add_history readline
fgets add_history
18
#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;
}
readline add_history
printf
fgets readline printf
free readline
input readline fgets
editline
19
editline
fatal error: editline/readline.h: No such file or directory #include
<editline/readline.h>
editline -ledit
editline
C
(portability)
C (preprocessor)
#
(include)
20
21
#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
#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
#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
#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
lispy>
\n
printf
printf
#ifndef
#define
_WIN32 Windows Linux Mac
26
19 50 Noam Chomsky
> The cat and mouse and dog walked on the carpet.
> The white cat and black dog walked on the carpet.
C if
if
(grammar)
27
"""" (
)
( Lisp )
mpc
( 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
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 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
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
"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
#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
#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
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)
( --> --> )
(Operator)
'+''-''*' '/'
( Number )
- --> 0 9
34
(Regular Expression)
[abcdef]
abcdef
[a-f]
a f
a?
a a
a*
0 a
a+
1 a
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
C <> ""
stdio.h
mpc.h
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
r error mpc_err_print
mpc_err_delete
<stdin>:1:4: error: expected one of '0123456789', whitespace, '-', one or more of one of '0123456789'
lispy>
37
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
a b :
aababa bbaa
a b
: ababab aba
%
39
mpc.h
mpc_ast_t
tag tag
expr|number|regex
tag
state
children_num children
children mpc_ast_t**
40
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
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
expr number
( ( )
)
number_of_nodes
C long ()
tag
contents
atoi
char* long
strcmp
char* 0
strstr
char*
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;
}
eval_op
43
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
}
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
46
47
S-
48
Q-
49
50
51
52
53
54
55
56