Browse Source

Add source of chapter 09, slightly adapted (move declarations to header file

T. Meissner 7 months ago
parent
commit
b65b9dd657
3 changed files with 484 additions and 0 deletions
  1. 13
    0
      chapter_09/Makefile
  2. 413
    0
      chapter_09/lispy.c
  3. 58
    0
      chapter_09/lispy.h

+ 13
- 0
chapter_09/Makefile View File

@@ -0,0 +1,13 @@
1
+MPC_DIR := ../mpc
2
+
3
+
4
+all: lispy
5
+
6
+
7
+%: %.c
8
+	cc -std=c11 -Wall $@.c ${MPC_DIR}/mpc.c -ledit -o $@
9
+
10
+
11
+.PHONY: clean
12
+clean:
13
+	rm -rf lispy

+ 413
- 0
chapter_09/lispy.c View File

@@ -0,0 +1,413 @@
1
+#include <stdio.h>
2
+#include <stdlib.h>
3
+#include <assert.h>
4
+#include "../mpc/mpc.h"
5
+
6
+
7
+/* If we are on Windows compile these functions */
8
+#ifdef _WIN32
9
+#include <string.h>
10
+
11
+static char buffer[2048];
12
+
13
+/* Fake readline function */
14
+char* readline(char* prompt) {
15
+    fputs(prompt, stdout);
16
+    fgets(buffer, 2048, stdin);
17
+    char* cpy = malloc(strlen(buffer)+1);
18
+    assert(cpy != NULL)
19
+    strcpy(cpy, buffer);
20
+    cpy[strlen(cpy)-1] = '\0';
21
+    return cpy;
22
+}
23
+
24
+/* Fake add_history function */
25
+void add_history(char* unused) {}
26
+
27
+/* Otherwise include the editline headers
28
+   could use __APPLE__ for detection of OSX */
29
+#else
30
+#include <editline/readline.h>
31
+#endif
32
+
33
+/* Include type and function declarations */
34
+#include "lispy.h"
35
+
36
+
37
+/* Construct a pointer to a new number lval */
38
+lval* lval_num(long x) {
39
+    lval* v = malloc(sizeof(lval));
40
+    assert(v != NULL);
41
+    v->type = LVAL_NUM;
42
+    v->num = x;
43
+    return v;
44
+}
45
+
46
+
47
+/* Construct a pointer to a new error lval */
48
+lval* lval_err(char* m) {
49
+    lval* v = malloc(sizeof(lval));
50
+    assert(v != NULL);
51
+    v->type = LVAL_ERR;
52
+    v->err = malloc(strlen(m)+1);
53
+    assert(v->err != NULL);
54
+    strcpy(v->err, m);
55
+    return v;
56
+}
57
+
58
+
59
+/* Construct a pointer to a new symbol lval */
60
+lval* lval_sym(char* s) {
61
+    lval* v = malloc(sizeof(lval));
62
+    assert(v != NULL);
63
+    v->type = LVAL_SYM;
64
+    v->sym = malloc(strlen(s)+1);
65
+    assert(v->sym != NULL);
66
+    strcpy(v->sym, s);
67
+    return v;
68
+}
69
+
70
+
71
+/* Construct a pointer to a new empty sexpr lval */
72
+lval* lval_sexpr(void) {
73
+    lval* v = malloc(sizeof(lval));
74
+    assert(v != NULL);
75
+    v->type = LVAL_SEXPR;
76
+    v->count = 0;
77
+    v->cell = NULL;
78
+    return v;
79
+}
80
+
81
+
82
+/* Free memory of an lval and all its members */
83
+void lval_del(lval* v) {
84
+
85
+    switch (v->type) {
86
+        /* Do nothing special for number type */
87
+        case LVAL_NUM:
88
+            break;
89
+
90
+        /* For err or sym free the string data */
91
+        case LVAL_ERR:
92
+            free(v->err);
93
+            break;
94
+        case LVAL_SYM:
95
+            free(v->sym);
96
+            break;
97
+
98
+        /* If sexpr then delete all elements inside */
99
+        case LVAL_SEXPR:
100
+            for (size_t i = 0; i < v->count; i++) {
101
+                lval_del(v->cell[i]);
102
+            }
103
+            /* Also free the memory allocated to contain
104
+               the pointers */
105
+            free(v->cell);
106
+            break;
107
+    }
108
+    /* Free the memory allocated for the lval struct itself */
109
+    free(v);
110
+}
111
+
112
+
113
+lval* lval_read_num(mpc_ast_t* t) {
114
+    errno = 0;
115
+    long x = strtol(t->contents, NULL, 10);
116
+    return errno != ERANGE ? lval_num(x)
117
+                           : lval_err("Invalid number");
118
+}
119
+
120
+
121
+lval* lval_read(mpc_ast_t* t) {
122
+
123
+    /* If symbol or number return conversion to that type */
124
+    if (strstr(t->tag, "number")) {
125
+        return lval_read_num(t);
126
+    }
127
+    if (strstr(t->tag, "symbol")) {
128
+        return lval_sym(t->contents);
129
+    }
130
+
131
+    /* If root (>) or sexpr then create empty list */
132
+    lval* x = NULL;
133
+    if (strcmp(t->tag, ">") == 0 || strstr(t->tag, "sexpr")) {
134
+        x = lval_sexpr();
135
+    }
136
+
137
+    /* Fill this list with any valid expression
138
+       contained within */
139
+    for (size_t i = 0; i < t->children_num; i++) {
140
+        if (strcmp(t->children[i]->contents, "(") == 0) {
141
+            continue;
142
+        }
143
+        if (strcmp(t->children[i]->contents, ")") == 0) {
144
+            continue;
145
+        }
146
+        if (strcmp(t->children[i]->contents, "{") == 0) {
147
+            continue;
148
+        }
149
+        if (strcmp(t->children[i]->contents, "}") == 0) {
150
+            continue;
151
+        }
152
+        if (strcmp(t->children[i]->tag, "regex") == 0) {
153
+            continue;
154
+        }
155
+        x = lval_add(x, lval_read(t->children[i]));
156
+    }
157
+
158
+    return x;
159
+}
160
+
161
+
162
+lval* lval_add(lval* v, lval* x) {
163
+    v->count++;
164
+    v->cell = realloc(v->cell, sizeof(lval*) * v->count);
165
+    assert(v->cell != NULL);
166
+    v->cell[v->count-1] = x;
167
+    return v;
168
+}
169
+
170
+
171
+void lval_expr_print(lval* v, char open, char close) {
172
+    /* Opening char */
173
+    putchar(open);
174
+
175
+    for (size_t i = 0; i < v->count; i++) {
176
+        /* Print value contained within */
177
+        lval_print(v->cell[i]);
178
+        /* Don't print trailing space if last element */
179
+        if (i != (v->count-1)) {
180
+            putchar(' ');
181
+        }
182
+    }
183
+    /* Opening char */
184
+    putchar(close);
185
+}
186
+
187
+
188
+/* Print an lval */
189
+void lval_print(lval* v) {
190
+
191
+    switch (v->type) {
192
+        /* In the case the type is a number print it
193
+           Then break out of the switch */
194
+        case LVAL_NUM:
195
+            printf("%li", v->num);
196
+            break;
197
+        /* In the case the type is an error */
198
+        case LVAL_ERR:
199
+            printf("Error: %s", v->err);
200
+            break;
201
+        case LVAL_SYM:
202
+            printf("%s", v->sym);
203
+            break;
204
+        case LVAL_SEXPR:
205
+            lval_expr_print(v, '(', ')');
206
+            break;
207
+    }
208
+
209
+}
210
+
211
+
212
+/* Print an lval followed by a newline */
213
+void lval_println(lval* v) {
214
+    lval_print(v);
215
+    putchar('\n');
216
+}
217
+
218
+
219
+lval* lval_eval_sexpr(lval* v) {
220
+
221
+    /* Evaluate children */
222
+    for (size_t i = 0; i < v->count; i++) {
223
+        v->cell[i] = lval_eval(v->cell[i]);
224
+    }
225
+
226
+    /* Error checking */
227
+    for (size_t i = 0; i < v->count; i++) {
228
+        if (v->cell[i]->type == LVAL_ERR) {
229
+            return lval_take(v, i);
230
+        }
231
+    }
232
+
233
+    /* Empty expression */
234
+    if (v->count == 0) {
235
+        return v;
236
+    }
237
+
238
+    /* Single expression */
239
+    if (v->count == 1) {
240
+        return lval_take(v, 0);
241
+    }
242
+
243
+    /* Ensure first element is symbol */
244
+    lval* f = lval_pop(v, 0);
245
+    if (f->type != LVAL_SYM) {
246
+        lval_del(f);
247
+        lval_del(v);
248
+        return lval_err("S-expression does not start with symbol!");
249
+    }
250
+
251
+    /* Call builtin with operator */
252
+    lval* result = builtin_op(v, f->sym);
253
+    lval_del(f);
254
+    return result;
255
+
256
+}
257
+
258
+
259
+lval* lval_eval(lval* v) {
260
+
261
+    /* Evaluate sexpressions */
262
+    if (v->type == LVAL_SEXPR) {
263
+        return lval_eval_sexpr(v);
264
+    }
265
+
266
+    /* All other lval types remain the same */
267
+    return v;
268
+
269
+}
270
+
271
+
272
+lval* lval_pop(lval* v, size_t i) {
273
+
274
+    /* Fine the item at i */
275
+    lval* x = v->cell[i];
276
+
277
+    /* Shift memory after the item at i over the top */
278
+    memmove(&v->cell[i], &v->cell[i+1],
279
+            sizeof(lval*) * (v->count-i-1));
280
+
281
+    /* Decrease the count of items in the list */
282
+    v->count--;
283
+
284
+    /* Reallocate the memory used */
285
+    v->cell = realloc(v->cell, sizeof(lval*) * v->count);
286
+    assert(v->cell != NULL);
287
+
288
+    return x;
289
+
290
+}
291
+
292
+lval* lval_take(lval* v, size_t i) {
293
+
294
+    lval* x = lval_pop(v, i);
295
+    lval_del(v);
296
+    return x;
297
+
298
+}
299
+
300
+
301
+lval* builtin_op(lval* a, char* op) {
302
+
303
+    /* Ensure all arguments are numbers */
304
+    for (size_t i = 0; i < a->count; i++) {
305
+        if (a->cell[i]->type != LVAL_NUM) {
306
+            lval_del(a);
307
+            return lval_err("Cannot operate on non-number!");
308
+        }
309
+    }
310
+
311
+    /* Pop the 1st element */
312
+    lval* x = lval_pop(a, 0);
313
+
314
+    /* If no arguments and sub then perform unary negation */
315
+    if (strcmp(op, "-") == 0 &&  a->count == 0) {
316
+        x->num = -x->num;
317
+    }
318
+
319
+    /* While there are still elements remaining */
320
+    while (a->count > 0) {
321
+        /* Pop the next element */
322
+        lval* y = lval_pop(a, 0);
323
+
324
+        if (strcmp(op, "+") == 0) {x->num += y->num;}
325
+        if (strcmp(op, "-") == 0) {x->num -= y->num;}
326
+        if (strcmp(op, "*") == 0) {x->num *= y->num;}
327
+        if (strcmp(op, "/") == 0) {
328
+            /* If second operand is zero return error */
329
+            if (y->num == 0) {
330
+                lval_del(x);
331
+                lval_del(y);
332
+                x = lval_err("Division by zero!");
333
+                break;
334
+            }
335
+            x->num /= y->num;
336
+        }
337
+        if (strcmp(op, "%") == 0) {x->num %= y->num;}
338
+        if (strcmp(op, "^") == 0) {x->num = (pow(x->num, y->num));}
339
+        if (strcmp(op, "min") == 0) {x->num = min(x->num, y->num);}
340
+        if (strcmp(op, "max") == 0) {x->num = max(x->num, y->num);}
341
+    }
342
+
343
+    lval_del(a);
344
+    return x;
345
+
346
+}
347
+
348
+
349
+long min(long x, long y) {
350
+    if (x <= y) {
351
+        return x;
352
+    } else {
353
+        return y;
354
+    }
355
+}
356
+
357
+
358
+long max(long x, long y) {
359
+    if (x >= y) {
360
+        return x;
361
+    } else {
362
+        return y;
363
+    }
364
+}
365
+
366
+
367
+int main(int argc, char const *argv[]) {
368
+
369
+    /* Create some parsers */
370
+    mpc_parser_t* Number = mpc_new("number");
371
+    mpc_parser_t* Symbol = mpc_new("symbol");
372
+    mpc_parser_t* Sexpr = mpc_new("sexpr");
373
+    mpc_parser_t* Expr = mpc_new("expr");
374
+    mpc_parser_t* Lispy = mpc_new("lispy");
375
+
376
+    /* Define them with the following language */
377
+    mpca_lang(MPCA_LANG_DEFAULT, parser,
378
+        Number, Symbol, Sexpr, Expr, Lispy);
379
+
380
+    /* Print version and exit information */
381
+    puts(lispy_version);
382
+    puts("Press Ctrl+c to exit\n");
383
+
384
+    /* In a never ending loop */
385
+    while (1) {
386
+        /* Output our prompt and get input */
387
+        char* input = readline("lispy> ");
388
+
389
+        /* Add input to history */
390
+        add_history(input);
391
+
392
+        /* Attempt to parse the user input */
393
+        mpc_result_t r;
394
+        if (mpc_parse("<stdin>", input, Lispy, &r)) {
395
+            /* On success evaluate the user input */
396
+            lval* x = lval_eval(lval_read(r.output));
397
+            lval_println(x);
398
+            lval_del(x);
399
+        } else {
400
+            /* Otherwise print the error */
401
+            mpc_err_print(r.error);
402
+            mpc_err_delete(r.error);
403
+        }
404
+
405
+        /* Free retrieved input */
406
+        free(input);
407
+    }
408
+
409
+    /* Undefine and delete our parsers */
410
+    mpc_cleanup(5, Number, Symbol, Sexpr, Expr, Lispy);
411
+
412
+    return 0;
413
+}

+ 58
- 0
chapter_09/lispy.h View File

@@ -0,0 +1,58 @@
1
+static char* lispy_version = "Lispy version 0.0.0.0.5";
2
+
3
+
4
+/* Parser language defintion */
5
+static char* parser =
6
+"                                                   \
7
+    number   : /-?[0-9]+/ ;                         \
8
+    symbol : '+' | '-' | '*' | '/' | '%' | '^' |  \
9
+    \"min\" | \"max\" ;                             \
10
+    sexpr    : '(' <expr>* ')' ;                    \
11
+    expr     : <number> | <symbol> | <sexpr> ;    \
12
+    lispy    : /^/ <expr>* /$/ ;                    \
13
+";
14
+
15
+
16
+/* Declare new lval struct */
17
+typedef struct lval {
18
+    int type;
19
+    long num;
20
+    /* Error & symbol types have some string data */
21
+    char* err;
22
+    char* sym;
23
+    /* Counter & pointer to a list of lval */
24
+    size_t count;
25
+    struct lval** cell;
26
+} lval;
27
+
28
+
29
+/* Create enumeration of possible lval types */
30
+enum {LVAL_NUM, LVAL_SYM, LVAL_SEXPR, LVAL_ERR};
31
+
32
+/* lval constructor functions */
33
+lval* lval_num(long x);
34
+lval* lval_err(char* m);
35
+lval* lval_sym(char* s);
36
+lval* lval_sexpr(void);
37
+
38
+/* lval destructor function */
39
+void lval_del(lval* v);
40
+
41
+/* lval manipulating functions */
42
+lval* lval_add(lval* v, lval* x);
43
+lval* lval_pop(lval* v, size_t i);
44
+lval* lval_take(lval* v, size_t i);
45
+
46
+lval* lval_read_num(mpc_ast_t* t);
47
+lval* lval_read(mpc_ast_t* t);
48
+lval* lval_eval_sexpr(lval* v);
49
+lval* lval_eval(lval* v);
50
+
51
+void lval_expr_print(lval* v, char open, char close);
52
+void lval_print(lval* v);
53
+void lval_println(lval* v);
54
+
55
+long min(long x, long y);
56
+long max(long x, long y);
57
+
58
+lval* builtin_op(lval* a, char* op);