void display(Object *root); void display_pair(Object *root) { display(root->car); if (root->cdr->type == OBJ_TYPE_PAIR) { printf(" "); display_pair(root->cdr); } else if (root->cdr->type == OBJ_TYPE_NIL) { return; } else { printf(" . "); display(root->cdr); } } void display(Object *root) { if (root == NULL) { return; } switch (root->type) { case OBJ_TYPE_FIXNUM: { printf("%zd", root->fixnum); } break; case OBJ_TYPE_BOOL: { if (root->boolean) { printf("true"); } else { printf("false"); } } break; case OBJ_TYPE_NIL: { printf("()"); } break; case OBJ_TYPE_STRING: { printf("\"%.*s\"", (int)root->string_n, root->string); } break; case OBJ_TYPE_SYMBOL: { printf(":%.*s", (int)root->symbol_n, root->symbol); } break; case OBJ_TYPE_PAIR: { printf("("); display_pair(root); printf(")"); } break; case OBJ_TYPE_PROCEDURE: { printf("#{procedure}"); } break; } } Object * eval(Object *root) { switch (root->type) { case OBJ_TYPE_FIXNUM: case OBJ_TYPE_BOOL: case OBJ_TYPE_NIL: case OBJ_TYPE_STRING: { return root; } break; case OBJ_TYPE_SYMBOL: { Object *value = find_environment_symbol(root); if (value == NULL) { printf("error: symbol not found: `"); display(root); printf("`\n"); return obj_nil; } return value; } break; case OBJ_TYPE_PAIR: { if (root->car->type == OBJ_TYPE_SYMBOL) { Object *value = find_environment_symbol(root->car); if (value == NULL) { printf("error: symbol not found: `"); display(root->car); printf("`\n"); return obj_nil; } if (value->type == OBJ_TYPE_PROCEDURE) { return value->proc(root->cdr); } } } break; default: { printf("error: can't eval type %d.\n", root->type); } break; } return obj_nil; } Object * proc_add(Object *args) { // Extract first parameter. Object *car = eval(args->car); if (car == NULL) { fprintf(stderr, "error: not enough arguments\n"); return obj_nil; } if (car->type != OBJ_TYPE_FIXNUM) { fprintf(stderr, "addition not supported for type %d\n", car->type); return obj_nil; } args = args->cdr; ssize_t tot = car->fixnum; while (args->type == OBJ_TYPE_PAIR) { Object *car = eval(args->car); if (car == NULL) { car = obj_nil; } if (car->type != OBJ_TYPE_FIXNUM) { fprintf(stderr, "addition not supported for type %d\n", car->type); return obj_nil; } tot += car->fixnum; args = args->cdr; } return make_fixnum(tot); } Object * proc_sub(Object *args) { // Extract first parameter. Object *car = eval(args->car); if (car == NULL) { fprintf(stderr, "error: not enough arguments\n"); return obj_nil; } if (car->type != OBJ_TYPE_FIXNUM) { fprintf(stderr, "error: sub not supported for type %d\n", car->type); return obj_nil; } args = args->cdr; ssize_t tot = car->fixnum; while (args->type == OBJ_TYPE_PAIR) { car = eval(args->car); if (car == NULL) { car = obj_nil; } if (car->type != OBJ_TYPE_FIXNUM) { fprintf(stderr, "error: sub not supported for type %d\n", car->type); return obj_nil; } tot -= car->fixnum; args = args->cdr; } return make_fixnum(tot); } Object * proc_mul(Object *args) { // Extract first parameter. Object *car = eval(args->car); if (car == NULL) { fprintf(stderr, "error: not enough arguments\n"); return obj_nil; } if (car->type != OBJ_TYPE_FIXNUM) { fprintf(stderr, "error: mult not supported for type %d\n", car->type); return obj_nil; } args = args->cdr; ssize_t tot = car->fixnum; while (args->type == OBJ_TYPE_PAIR) { Object *car = eval(args->car); if (car == NULL) { car = obj_nil; } if (car->type != OBJ_TYPE_FIXNUM) { fprintf(stderr, "error: mult not supported for type %d\n", car->type); return obj_nil; } tot *= car->fixnum; args = args->cdr; } return make_fixnum(tot); } Object * proc_div(Object *args) { // Extract first parameter. Object *car = eval(args->car); if (car == NULL) { fprintf(stderr, "error: not enough arguments\n"); return obj_nil; } args = args->cdr; ssize_t tot = car->fixnum; while (args->type == OBJ_TYPE_PAIR) { Object *car = eval(args->car); if (car == NULL) { car = obj_nil; } if (car->type != OBJ_TYPE_FIXNUM) { fprintf(stderr, "error: div not supported for type %d\n", car->type); return obj_nil; } if (car->fixnum == 0) { fprintf(stderr, "error: division by zero\n"); return obj_nil; } tot /= car->fixnum; args = args->cdr; } return make_fixnum(tot); } Object * proc_display(Object *args) { if (args == NULL) { return obj_nil; } if (args->type == OBJ_TYPE_PAIR) { display(eval(args->car)); } return obj_nil; }