-
Notifications
You must be signed in to change notification settings - Fork 0
/
prompt.c
133 lines (87 loc) · 3.13 KB
/
prompt.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/*
Interactive Prompt
REPL
read-evaluate-print loop
A way is needed to interact with this toy lisp.
C uses a compiler, where you can change the program, recompile and run it.
It would be good if we could do something better, and interact with the
language dynamically. Then we test its behaviour under a number of conditions
very quickly.
This is a program that prompts the user for some input, and when supplied with
it, replies back with some message. This system is called a REPL.
*/
/* basic setup - a loop */
#include <stdio.h>
#include <stdlib.h>
#include "mpc.h" /* file is local, use "" */
#include <editline/readline.h>
/* use operator string to decide 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;
}
/* evaluation function */
/* ok, now this is recursion, and it is unlike the way the author had described
it */
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) {
/* 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);
/* print version and exit information */
puts("Toy Lisp v0.1");
puts("Press control+c to Exit\n");
/* a never ending loop */
while (1) {
/* output prompt and get input */
char* input = readline("toy-lisp>>> ");
/* add input to history */
add_history(input);
/* echo input back to user */
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 {
/* otherwise print the error */
mpc_err_print(r.error);
mpc_err_delete(r.error);
}
/* free retrieved input */
free(input);
}
/* undefine and delete our parsers */
mpc_cleanup(4, Number, Operator, Expr, Lispy);
return 0;
}