Browse Source

chapter 8

master
red 4 years ago
parent
commit
d0d4906088
5 changed files with 163 additions and 1 deletions
  1. +8
    -0
      CMakeLists.txt
  2. +3
    -1
      README.md
  3. +77
    -0
      eval.c
  4. +21
    -0
      eval.h
  5. +54
    -0
      main.c

+ 8
- 0
CMakeLists.txt View File

@@ -0,0 +1,8 @@
cmake_minimum_required(VERSION 3.12)
project(crisp C)

set(CMAKE_C_STANDARD 99)

add_executable(main main.c mpc.c eval.c eval.h)

target_link_libraries(main edit)

+ 3
- 1
README.md View File

@@ -1,3 +1,5 @@
# crisp

lisp but crispier
lisp but crispier

follows the book http://www.buildyourownlisp.com

+ 77
- 0
eval.c View File

@@ -0,0 +1,77 @@
//
// Created by red on 05/12/19.
//

#include "eval.h"

// create number type cval
cval cval_num(long x) {
cval v;
v.type = CVAL_NUM;
v.num = x;
return v;
}

// create error type cval
cval cval_err(int x){
cval v;
v.type = CVAL_ERR;
v.err = x;
return v;
}


void cval_print(cval v) {
switch (v.type) {
case CVAL_NUM: printf("%li", v.num); break;
case CVAL_ERR: {
switch (v.err) {
case CERR_DIV_ZERO: printf("Error: Division by zero"); break;
case CERR_BAD_OP: printf("Error: Invalid operator"); break;
case CERR_BAD_NUM: printf("Error: Invalid number"); break;
default: break;
}
}
default: break;
}
}

void cval_println(cval v) {
cval_print(v);
putchar('\n');
}

cval eval_op(cval x, char* op, cval y) {
if (x.type == CVAL_ERR) {return x;}
if (y.type == CVAL_ERR) {return y;}
switch (*op) {
case '+': return cval_num(x.num + y.num);
case '-': return cval_num(x.num - y.num);
case '*': return cval_num(x.num * y.num);
//return error
case '/': return y.num == 0 ? cval_err(CERR_DIV_ZERO) : cval_num(x.num / y.num);
default: return cval_err(CERR_BAD_OP);
}
}

cval eval(mpc_ast_t* t) {

if (strstr(t->tag, "number")) {
errno = 0;
long x = strtol(t->contents, NULL, 10);
return errno != ERANGE ? cval_num(x) : cval_err(CERR_BAD_NUM);
}

// the operator is always the second child
char* op = t->children[1]->contents;
cval x = eval(t->children[2]);

// iterate over the remaining children and combine
int i = 3;
while (strstr(t->children[i]->tag, "expr")) {
x = eval_op(x, op, eval(t->children[i]));
i++;
}

return x;
}

+ 21
- 0
eval.h View File

@@ -0,0 +1,21 @@
//
// Created by red on 05/12/19.
//


#include "mpc.h"

#ifndef CRISP_EVAL_H
#define CRISP_EVAL_H
typedef struct {
int type;
long num;
int err;
} cval;
enum { CVAL_NUM, CVAL_ERR };
enum { CERR_DIV_ZERO, CERR_BAD_OP, CERR_BAD_NUM };
cval eval(mpc_ast_t* t);
void cval_print(cval v);
void cval_println(cval v);

#endif //CRISP_EVAL_H

+ 54
- 0
main.c View File

@@ -0,0 +1,54 @@
//
// Created by red on 03/12/19.
//

#include <stdio.h>
#include <editline/readline.h>
#include <editline/history.h>
#include <stdlib.h>
#include "mpc.h"
#include "eval.h"

#pragma clang diagnostic ignored "-Wmissing-noreturn"

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* Crisp = mpc_new("crisp");

mpca_lang(MPCA_LANG_DEFAULT,
" number : /-?[0-9]+/ ;"
" operator : '+' | '-' | '*' | '/' ;"
" expr : <number> | '(' <operator> <expr>+ ')' ;"
" crisp : /^/ <operator> <expr>+ /$/ ;",
Number, Operator, Expr, Crisp);

puts("Crisp v.0.0.1");
puts("Press Ctrl-C to exit\n");

for (;;) {

char* input = readline("crisp> ");
add_history(input);

// attempt to parse input
mpc_result_t r;
if (mpc_parse("<stdin>", input, Crisp, &r)) {

cval result = eval(r.output);
cval_println(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, Crisp);
return EXIT_SUCCESS;
}

Loading…
Cancel
Save