Replacing mpc

The output of mpc was an Abstract Syntax Tree, but because our language is so simple, when we replace it we’re going to go directly from the input string to an S-Expressions (which is pretty much like abstract syntax tree anyway). So let us declare a function which takes some string s, some pointer to a position in that string i and some terminal character end and which outputs an lval. We’ll call it lval_read_expr.

  1. lval* lval_read_expr(char* s, int* i, char end);

We’ll define the implementation later. For now lets go ahead and replace the places we call mpc with this new function. For error handling we’ll get lval_read_expr to return an error lval if something goes wrong. The terminal character when we’re reading from a C string is just the null character \0.

  1. char* input = readline("lispy> ");
  2. /* Read from input to create an S-Expr */
  3. int pos = 0;
  4. lval* expr = lval_read_expr(input, &pos, '\0');
  5. /* Evaluate and print input */
  6. lval* x = lval_eval(e, expr);

We also need to replace mpc in our function builtin_load. Here, because we only support strings in our read function, we first need to load in the contents of the file. To do this we use fseek and ftell to find out how many characters are in the file before allocating a string of that size (plus one) and reading the file into it.

  1. lval* builtin_load(lenv* e, lval* a) {
  2. LASSERT_NUM("load", a, 1);
  3. LASSERT_TYPE("load", a, 0, LVAL_STR);
  4. /* Open file and check it exists */
  5. FILE* f = fopen(a->cell[0]->str, "rb");
  6. if (f == NULL) {
  7. lval* err = lval_err("Could not load Library %s", a->cell[0]->str);
  8. lval_del(a);
  9. return err;
  10. }
  11. /* Read File Contents */
  12. fseek(f, 0, SEEK_END);
  13. long length = ftell(f);
  14. fseek(f, 0, SEEK_SET);
  15. char* input = calloc(length+1, 1);
  16. fread(input, 1, length, f);
  17. fclose(f);

We can then easily read from this string as we did in main.

  1. /* Read from input to create an S-Expr */
  2. int pos = 0;
  3. lval* expr = lval_read_expr(input, &pos, '\0');
  4. free(input);
  5. /* Evaluate all expressions contained in S-Expr */
  6. if (expr->type != LVAL_ERR) {
  7. while (expr->count) {
  8. lval* x = lval_eval(e, lval_pop(expr, 0));
  9. if (x->type == LVAL_ERR) { lval_println(x); }
  10. lval_del(x);
  11. }
  12. } else {
  13. lval_println(expr);
  14. }
  15. lval_del(expr);
  16. lval_del(a);
  17. return lval_sexpr();
  18. }

And with those calls replaced we can start defining lval_read_expr.