Beispiel #1
0
Value * bind_names_values(Environment *env, Value *names, Value *values) {

    assert(env != NULL);
    assert(names != NULL);
    assert(values != NULL);

    /* Bind each value under its specified name. */
    while (is_cons_pair(names)) {
        Value *argname = get_car(names);

        if (is_nil(values))
            return make_error("not enough values to complete bindings!");

        assert(is_cons_pair(values));

        create_binding(env, argname->string_val, get_car(values));

        names = get_cdr(names);
        values = get_cdr(values);
    }

    assert(is_nil(names));
    if (!is_nil(values))
        return make_error("too many values for the specified bindings!");

    return NULL;
}
Beispiel #2
0
/* use *args_io to override *stdin* | *stdout* if not NIL */
static cell_t *new_frame_io(secd_t *secd, cell_t *args_io, cell_t *prevenv) {
    cell_t *prev_io = get_car(prevenv)->as.frame.io;
    if (is_nil(args_io))
        return prev_io; /* share previous i/o */

    if (is_nil(get_car(args_io)))
        args_io->as.cons.car = share_cell(secd, get_car(prev_io));
    if (is_nil(get_cdr(args_io)))
        args_io->as.cons.cdr = share_cell(secd, get_cdr(prev_io));
    return args_io; /* set a new i/o */
}
Beispiel #3
0
lisp_object* assoc(lisp_object* obj, lisp_object* env)
{
  //env must be ((dummy . dummy) (a . 1) (b . 3) ...)
  env = get_cdr(env);
  for(env = get_cdr(env); null(env); env = get_cdr(env)){
    if(get_car(get_car(env)) == obj){
      return get_car(env);
    }
  }
  return create_empty_list();
}
Beispiel #4
0
void dbg_print_cell(secd_t *secd, const cell_t *c) {
    if (is_nil(c)) {
         secd_printf(secd, "NIL\n");
         return;
    }
    char buf[128];
    if (c->nref > DONT_FREE_THIS - 100000) strncpy(buf, "-", 64);
    else snprintf(buf, 128, "%ld", (long)c->nref);
    printf("[%ld]^%s: ", cell_index(secd, c), buf);

    switch (cell_type(c)) {
      case CELL_CONS:
        printf("CONS([%ld], [%ld])\n",
               cell_index(secd, get_car(c)), cell_index(secd, get_cdr(c)));
        break;
      case CELL_FRAME:
        printf("FRAME(syms: [%ld], vals: [%ld])\n",
               cell_index(secd, get_car(c)), cell_index(secd, get_cdr(c)));
        break;
      case CELL_INT:  printf("%d\n", c->as.num); break;
      case CELL_CHAR:
        if (isprint(c->as.num)) printf("#\\%c\n", (char)c->as.num);
        else printf("#x%x\n", c->as.num);
        break;
      case CELL_OP:
        sexp_print_opcode(secd, secd->output_port, c->as.op);
        printf("\n");
        break;
      case CELL_FUNC: printf("*%p()\n", c->as.ptr); break;
      case CELL_KONT: printf("KONT[%ld, %ld, %ld]\n",
                             cell_index(secd, c->as.kont.stack),
                             cell_index(secd, c->as.kont.env),
                             cell_index(secd, c->as.kont.ctrl)); break;
      case CELL_ARRAY: printf("ARR[%ld]\n",
                               cell_index(secd, arr_val(c, 0))); break;
      case CELL_STR: printf("STR[%ld\n",
                             cell_index(secd, (cell_t*)strval(c))); break;
      case CELL_SYM: printf("SYM[%08x]='%s'\n",
                             symhash(c), symname(c)); break;
      case CELL_BYTES: printf("BVECT[%ld]\n",
                               cell_index(secd, (cell_t*)strval(c))); break;
      case CELL_REF: printf("REF[%ld]\n",
                             cell_index(secd, c->as.ref)); break;
      case CELL_ERROR: printf("ERR[%s]\n", errmsg(c)); break;
      case CELL_ARRMETA: printf("META[%ld, %ld]\n",
                                 cell_index(secd, mcons_prev((cell_t*)c)),
                                 cell_index(secd, mcons_next((cell_t*)c))); break;
      case CELL_UNDEF: printf("#?\n"); break;
      case CELL_FREE: printf("FREE\n"); break;
      default: printf("unknown type: %d\n", cell_type(c));
    }
}
Beispiel #5
0
void add_bind_to_env(lisp_object* env, lisp_object* sym, lisp_object* obj)
{
  lisp_object* tmp = create_cons();
  //env must be ((dummy . dummy) (a . 1) (b . 3) ...)

  set_cdr(tmp, get_cdr(env));
  set_cdr(get_cdr(env), tmp);

  set_car(tmp, create_cons());

  set_car(get_car(tmp), sym);
  set_cdr(get_car(tmp), obj);
  return;
}
Beispiel #6
0
lisp_object* evls(lisp_object* arg, lisp_object* env)
{
  lisp_object *op, *tmp, *ret;
  tmp = ret = create_cons();
  add_protect(ret);

  for(op = arg; !null(op); op = get_cdr(op)){
    set_cdr(tmp, create_cons());
    tmp = get_cdr(tmp);
    add_protect(tmp);
    set_car(tmp,eval(op, env));
  }
  set_cdr(tmp, create_empty_list());
  return get_cdr(ret);
}
Beispiel #7
0
lisp_object* LF_eq(lisp_object* obj)
{
  if(get_car(obj) == get_car(get_cdr(obj))){
    return create_boolean(1);
  }
  return create_boolean(0);
}
Beispiel #8
0
/* check arity;
 * possibly rewrite dot-lists into regular arguments;
 * look for overriden *stdin*|*stdout* */
static cell_t *
walk_through_arguments(secd_t *secd, cell_t *frame, cell_t **args_io) {
    cell_t *symlist = get_car(frame);
    cell_t *vallist = get_cdr(frame);

    size_t valcount = 0;

    while (not_nil(symlist)) {
        if (is_symbol(symlist)) {
            break;
        }

        if (is_nil(vallist)) {
            errorf(";; arity mismatch: %zd argument(s) is not enough\n", valcount);
            return new_error(secd, SECD_NIL,
                    "arity mismatch: %zd argument(s) is not enough", valcount);
        }

        cell_t *sym = get_car(symlist);

        check_io_args(secd, sym, get_car(vallist), args_io);

        cell_t *nextsyms = list_next(secd, symlist);
        cell_t *nextvals = list_next(secd, vallist);

        ++valcount;

        symlist = nextsyms;
        vallist = nextvals;
    }

    return SECD_NIL;
}
Beispiel #9
0
Datei: memory.c Projekt: 8l/SECD
cell_t *pop_free(secd_t *secd) {
    cell_t *cell;
    if (not_nil(secd->free)) {
        /* take a cell from the list */
        cell = secd->free;
        secd->free = get_cdr(secd->free);
        if (secd->free)
            secd->free->as.cons.car = SECD_NIL;
        memdebugf("NEW [%ld]\n", cell_index(secd, cell));
        -- secd->free_cells;
    } else {
        assert(secd->free_cells == 0,
               "pop_free: free=NIL when nfree=%zd\n", secd->free_cells);
        /* move fixedptr */
        if (secd->fixedptr >= secd->arrayptr)
            return &secd_out_of_memory;

        cell = secd->fixedptr;
        ++ secd->fixedptr;
        memdebugf("NEW [%ld] ++\n", cell_index(secd, cell));
    }

    cell->type = CELL_UNDEF;
    cell->nref = 0;
    return cell;
}
Beispiel #10
0
lisp_object* LF_cons(lisp_object* obj)
{
  lisp_object* cons = create_cons();
  set_car(cons, get_car(obj));
  set_cdr(cons, get_car(get_cdr(obj)));
  return cons;
}
Beispiel #11
0
void secd_print_env(secd_t *secd) {
    cell_t *env = secd->env;
    int i = 0;
    secd_printf(secd, ";;Environment:\n");
    while (not_nil(env)) {
        secd_printf(secd, ";;  Frame #%d:\n", i++);
        cell_t *frame = get_car(env);
        cell_t *symlist = get_car(frame);
        cell_t *vallist = get_cdr(frame);

        while (not_nil(symlist)) {
            if (is_symbol(symlist)) {
                secd_printf(secd, ";;  . %s\t=>\t", symname(symlist));
                dbg_print_cell(secd, vallist);
                break;
            }
            cell_t *sym = get_car(symlist);
            cell_t *val = get_car(vallist);
            if (!is_symbol(sym)) {
                errorf("print_env: not a symbol at *%p in symlist\n", sym);
                dbg_printc(secd, sym);
            }
            secd_printf(secd, ";;    %s\t=>\t", symname(sym));
            dbg_print_cell(secd, val);

            symlist = list_next(secd, symlist);
            vallist = list_next(secd, vallist);
        }

        env = list_next(secd, env);
    }
}
Beispiel #12
0
SE *get_cdr() {
  SE *hd,*tl;
  get_token();
  if(token.type==TRPAR) return NIL;
  hd=get_se();
  tl=get_cdr();
  return new_cons(hd,tl);
}
Beispiel #13
0
lisp_object* eval(lisp_object* obj, lisp_object* env)
{
  data_type type = get_type_tag(obj);
  lisp_object *opecode, *ret;
  
  switch(type){
  case TYPE_BOOLEAN:
  case TYPE_NUMBER:
  case TYPE_CHAR:
  case TYPE_SUBR:
  case TYPE_FSUBR:
  case TYPE_EXPR:
  case TYPE_FEXPR:
  case TYPE_STRING:
  case TYPE_PORT:
  case TYPE_NULL:
  case TYPE_VECTOR:
    return obj;
  case TYPE_SYMBOL:
    ret = assoc(obj, env);
    if(null(ret)){
      fprintf(stderr, "eval:undefined variable\n");
      return create_empty_list();// たぶん、toplevelに戻ったほうがいい
    }
    return ret;
  case TYPE_CONS:
    opecode = eval(get_car(obj), env);
    type = get_type_tag(opecode);
    switch(type){
    case TYPE_SUBR:
    case TYPE_EXPR:
      return apply(opecode, evls(get_cdr(obj), env));
    case TYPE_FSUBR:
    case TYPE_FEXPR:
      return apply(opecode, get_cdr(obj));
    default:
      fprintf(stderr, "eval:not function\n");
      return create_empty_list();
    }
  default:
    fprintf(stderr, "eval:undefined type\n");
    return create_empty_list();
  }
}
Beispiel #14
0
cell_t *lookup_env(secd_t *secd, const char *symbol, cell_t **symc) {
    cell_t *env = secd->env;
    assert(cell_type(env) == CELL_CONS,
            "lookup_env: environment is not a list");

    cell_t *res = lookup_fake_variables(secd, symbol);
    if (not_nil(res))
        return res;

    hash_t symh = secd_strhash(symbol);

    while (not_nil(env)) {       // walk through frames
        cell_t *frame = get_car(env);
        if (is_nil(frame)) {
            /* skip omega-frame */
            env = list_next(secd, env);
            continue;
        }

        cell_t *symlist = get_car(frame);
        cell_t *vallist = get_cdr(frame);

        while (not_nil(symlist)) {   // walk through symbols
            if (is_symbol(symlist)) {
                if (symh == symhash(symlist) && str_eq(symbol, symname(symlist))) {
                    if (symc != NULL) *symc = symlist;
                    return vallist;
                }
                break;
            }

            cell_t *curc = get_car(symlist);
            assert(is_symbol(curc),
                   "lookup_env: variable at [%ld] is not a symbol\n",
                   cell_index(secd, curc));

            if (symh == symhash(curc) && str_eq(symbol, symname(curc))) {
                if (symc != NULL) *symc = curc;
                return get_car(vallist);
            }

            symlist = list_next(secd, symlist);
            vallist = list_next(secd, vallist);
        }

        env = list_next(secd, env);
    }
    //errorf(";; error in lookup_env(): %s not found\n", symbol);
    return new_error(secd, SECD_NIL, "Lookup failed for: '%s'", symbol);
}
Beispiel #15
0
Datei: memory.c Projekt: 8l/SECD
/* Deallocation */
cell_t *drop_dependencies(secd_t *secd, cell_t *c) {
    enum cell_type t = cell_type(c);
    switch (t) {
      case CELL_SYM:
        if (c->as.sym.size != DONT_FREE_THIS)
            free((char *)c->as.sym.data);
            /* TODO: this silently ignores symbol memory corruption */
            c->as.sym.size = DONT_FREE_THIS;
        break;
      case CELL_FRAME:
        drop_cell(secd, c->as.frame.io);
        // fall through
      case CELL_CONS:
        if (not_nil(c)) {
            drop_cell(secd, get_car(c));
            drop_cell(secd, get_cdr(c));
        }
        break;
      case CELL_STR:
      case CELL_ARRAY:
        drop_array(secd, arr_mem(c));
        break;
      case CELL_REF:
        drop_cell(secd, c->as.ref);
        break;
      case CELL_PORT:
        secd_pclose(secd, c);
        break;
      case CELL_ARRMETA:
        if (c->as.mcons.cells) {
            size_t size = arrmeta_size(secd, c);
            size_t i;

            /* free the items */
            for (i = 0; i < size; ++i) {
                /* don't free uninitialized */
                cell_t *ith = meta_mem(c) + i;
                if (cell_type(ith) != CELL_UNDEF)
                    drop_dependencies(secd, ith);
            }
        }
        break;
      case CELL_INT: case CELL_FUNC: case CELL_OP:
      case CELL_ERROR: case CELL_UNDEF:
        return c;
      default:
        return new_error(secd, "drop_dependencies: unknown cell_type 0x%x", t);
    }
    return c;
}
Beispiel #16
0
cell_t *secd_insert_in_frame(secd_t *secd, cell_t *frame, cell_t *sym, cell_t *val) {
    cell_t *old_syms = get_car(frame);
    cell_t *old_vals = get_cdr(frame);

    // an interesting side effect: since there's no check for
    // re-binding an existing symbol, we can create multiple
    // copies of it on the frame, the last added is found
    // during value lookup, but the old ones are persistent
    frame->as.cons.car = share_cell(secd, new_cons(secd, sym, old_syms));
    frame->as.cons.cdr = share_cell(secd, new_cons(secd, val, old_vals));

    drop_cell(secd, old_syms); drop_cell(secd, old_vals);
    return frame;
}
Beispiel #17
0
SE *get_se()
{
  switch(token.type)
    {
    case TEOF: return new_sym(strdup("#eof"));
    case TNUM: return new_num(atoi(token.buf));
    case TSYM: return new_sym(strdup(token.buf));
    case TQUOTE: get_token(); /* ! */
                 return new_cons(new_sym(strdup("quote")),
                                 new_cons(get_se(),NIL));
    case TLPAR: return get_cdr();
    default: break; /* err! */
    }
 return NIL; /* notreached */
}
Beispiel #18
0
cell_t *setup_frame(secd_t *secd, cell_t *argnames, cell_t *argvals, cell_t *env) {
    cell_t *args_io = SECD_NIL;

    /* setup the new frame */
    cell_t *frame = new_frame(secd, argnames, argvals);

    cell_t *ret = walk_through_arguments(secd, frame, &args_io);
    assert_cell(ret, "setup_frame: argument check failed");

    cell_t *new_io = new_frame_io(secd, args_io, env);
    assert_cell(new_io, "setup_frame: failed to set new frame I/O\n");

    frame->as.frame.io = share_cell(secd, new_io);
    secd->input_port = get_car(new_io);
    secd->output_port = get_cdr(new_io);

    return frame;
}
Beispiel #19
0
Value * evaluate(Environment *env, Value *expr) {

    EvaluationContext *ctx;
    Value *temp, *result;

    Value *operator;
    Value *operand_val, *operand_cons;
    Value *operands, *operands_end, *nil_value;
    int num_operands;

    /* Set up a new evaluation context and record our local variables, so that
     * the garbage-collector can see any temporary values we use.
     */
    ctx = push_new_evalctx(env, expr);
    evalctx_register(&temp);
    evalctx_register(&result);
    evalctx_register(&operator);
    evalctx_register(&operand_val);
    evalctx_register(&operand_cons);
    evalctx_register(&operands);
    evalctx_register(&operands_end);
    evalctx_register(&nil_value);

#ifdef VERBOSE_EVAL
    printf("\nEvaluating expression:  ");
    print_value(stdout, expr);
    printf("\n");
#endif

    /* If this is a special form, evaluate it.  Otherwise, this function will
     * simply pass the input through to the result.
     */
    result = eval_special_form(env, expr);
    if (result != expr)
        goto Done;    /* It was a special form. */

    /*
     * If the input is an atom, we need to resolve it to a value, using the
     * current environment.
     */

    if (is_atom(expr)) {
        /* Treat the atom as a name - resolve it to a value. */
        result = resolve_binding(env, expr->string_val);
        if (result == NULL) {
            result = make_error("couldn't resolve name \"%s\" to a value!",
                expr->string_val);
        }

        goto Done;
    }

    /*
     * If the input isn't an atom and isn't a cons-pair, then assume it's a
     * value that doesn't need evaluating, and just return it.
     */

    if (!is_cons_pair(expr)) {
        result = expr;
        goto Done;
    }

    /*
     * Evaluate operator into a lambda expression.
     */

    temp = get_car(expr);

    operator = evaluate(env, temp);
    if (is_error(operator)) {
        result = operator;
        goto Done;
    }
    if (!is_lambda(operator)) {
        result = make_error("operator is not a valid lambda expression");
        goto Done;
    }

#ifdef VERBOSE_EVAL
    printf("Operator:  ");
    print_value(stdout, operator);
    printf("\n");
#endif

    /*
     * Evaluate each operand into a value, and build a list up of the values.
     */

#ifdef VERBOSE_EVAL
    printf("Starting evaluation of operands.\n");
#endif

    num_operands = 0;
    operands_end = NULL;
    operands = nil_value = make_nil();

    temp = get_cdr(expr);
    while (is_cons_pair(temp)) {
        Value *raw_operand;

        num_operands++;

        /* This is the raw unevaluated value. */
        raw_operand = get_car(temp);

        /* Evaluate the raw input into a value. */

        operand_val = evaluate(env, raw_operand);
        if (is_error(operand_val)) {
            result = operand_val;
            goto Done;
        }

        operand_cons = make_cons(operand_val, nil_value);
        if (operands_end != NULL)
            set_cdr(operands_end, operand_cons);
        else
            operands = operand_cons;

        operands_end = operand_cons;

        temp = get_cdr(temp);
    }

    /*
     * Apply the operator to the operands, to generate a result.
     */

    if (operator->lambda_val->native_impl) {
        /* Native lambdas don't need an environment created for them.  Rather,
         * we just pass the list of arguments to the native function, and it
         * processes the arguments as needed.
         */
        result = operator->lambda_val->func(num_operands, operands);
    }
    else {
        /* These don't need registered on the explicit stack.  (I hope.) */
        Environment *child_env;
        Value *body_iter;

        /* It's an interpreted lambda.  Create a child environment, then
         * populate it with values based on the lambda's argument-specification
         * and the input operands.
         */
        child_env = make_environment(operator->lambda_val->parent_env);
        temp = bind_arguments(child_env, operator->lambda_val, operands);
        if (is_error(temp)) {
            result = temp;
            goto Done;
        }

        /* Evaluate each expression in the lambda, using the child environment.
         * The result of the last expression is the result of the lambda.
         */
        body_iter = operator->lambda_val->body;
        do {
            result = evaluate(child_env, get_car(body_iter));
            body_iter = get_cdr(body_iter);
        }
        while (!is_nil(body_iter));
    }

Done:

#ifdef VERBOSE_EVAL
    printf("Result:  ");
    print_value(stdout, result);
    printf("\n\n");
#endif

    /* Record the result and then perform garbage-collection. */
    pop_evalctx(result);
    collect_garbage();

    return result;
}
Beispiel #20
0
cell_t *serialize_cell(secd_t *secd, cell_t *cell) {
    cell_t *opt = SECD_NIL;
    switch (cell_type(cell)) {
    case CELL_CONS: {
        cell_t *cdrc = chain_index(secd, get_cdr(cell), SECD_NIL);
        opt = chain_index(secd, get_car(cell), cdrc);
    }
    break;
    case CELL_PORT:
        opt = secd_pserialize(secd, cell);
        break;
    case CELL_SYM:
        opt = new_cons(secd, cell, SECD_NIL);
        break;
    case CELL_INT:
    case CELL_CHAR:
        opt = new_cons(secd, cell, SECD_NIL);
        break;
    case CELL_OP: {
        cell_t *namec = new_symbol(secd, opcode_table[ cell->as.op ].name);
        opt = new_cons(secd, namec, SECD_NIL);
    }
    break;
    case CELL_FUNC:
        opt = new_cons(secd, new_number(secd, (long)cell->as.ptr), SECD_NIL);
        break;
    case CELL_ARRMETA: {
        cell_t *typec = chain_sym(secd,
                                  (cell->as.mcons.cells ? "cell" : "byte"),
                                  SECD_NIL);
        cell_t *nextc = chain_index(secd, mcons_next(cell), typec);
        opt = chain_index(secd, mcons_prev(cell), nextc);
    }
    break;
    case CELL_FRAME: {
        cell_t *ioc = chain_index(secd, cell->as.frame.io, SECD_NIL);
        cell_t *nextc = chain_index(secd, cell->as.frame.cons.cdr, ioc);
        opt = chain_index(secd, cell->as.frame.cons.car, nextc);
    }
    break;
    case CELL_KONT: {
        cell_t *kctrl = chain_index(secd, cell->as.kont.ctrl, SECD_NIL);
        cell_t *kenv  = chain_index(secd, cell->as.kont.env,  kctrl);
        opt = chain_index(secd, cell->as.kont.stack, kenv);
    }
    break;
    case CELL_FREE: {
        cell_t *nextc = chain_index(secd, get_cdr(cell), SECD_NIL);
        opt = chain_index(secd, get_car(cell), nextc);
    }
    break;
    case CELL_REF:
        opt = chain_index(secd, cell->as.ref, SECD_NIL);
        break;
    case CELL_ERROR:
        opt = chain_string(secd, errmsg(cell), SECD_NIL);
        break;
    case CELL_UNDEF:
        opt = SECD_NIL;
        break;
    case CELL_ARRAY:
        opt = chain_index(secd, arr_val(cell, -1), SECD_NIL);
        break;
    case CELL_STR:
    case CELL_BYTES:
        opt = chain_index(secd, arr_meta((cell_t *)strmem(cell)), SECD_NIL);
        break;
    }
    opt = new_cons(secd, secd_type_sym(secd, cell), opt);
    cell_t *refc = new_cons(secd, new_number(secd, cell->nref), opt);
    return new_cons(secd, new_number(secd, cell - secd->begin), refc);
}
Beispiel #21
0
/*!
 * This helper function takes an interpreted lambda expression, a list of
 * evaluated operands for the lambda, and the environment that the lambda will
 * be run in, and binds each operand into the environment with the argument name
 * specified in the lambda's argument list.
 *
 * The function returns NULL on success, or a Value* of type T_Error if
 * something horrible happens along the way.  For example, the function may
 * receive too many or too few arguments, or the interpreter may not have enough
 * memory to construct a specific binding.
 */
Value * bind_arguments(Environment *child_env, Lambda *lambda, Value *operands) {
    Value *argname_iter, *argval_iter;

    assert(child_env != NULL);
    assert(lambda != NULL);
    assert(!lambda->native_impl);
    assert(operands != NULL);

    /* Populate the child environment with values based on the lambda's
     * argument-specification, and the input operands.
     */
    argname_iter = lambda->arg_spec;
    argval_iter = operands;
    if (is_atom(argname_iter)) {
        /* Entire operand list gets bound under a single name. */
        create_binding(child_env, argname_iter->string_val, operands);
    }
    else {
        /* Bind each operand under its specified name.
         *
         * TODO:  Find a way to use bind_names_values(), one day...
         */
        assert(is_cons_pair(argname_iter));
        do {
            Value *argname = get_car(argname_iter);

            if (is_nil(argval_iter))
                return make_error("not enough arguments for lambda!");

            assert(is_cons_pair(operands));

            create_binding(child_env, argname->string_val,
                           get_car(argval_iter));

            argname_iter = get_cdr(argname_iter);
            argval_iter = get_cdr(argval_iter);
        }
        while (is_cons_pair(argname_iter));

        if (is_nil(argname_iter) && !is_nil(argval_iter))
            return make_error("too many arguments for lambda!");

        /* If argname_iter is an atom then the argument-list was an improper
         * list, and the remainder of the operands get bound under this name.
         */
        if (is_atom(argname_iter)) {
            create_binding(child_env, argname_iter->string_val, argval_iter);
        }
        else {
            /* The lambda special-form should have constructed the argument
             * specification properly, so this assertion should never fail.
             */
            assert(is_nil(argname_iter));
        }
    }

    /* NULL just means "success" here.  The only other thing this function might
     * return is a Value of type T_Error, if something awful happened...
     */
    return NULL;
}
Beispiel #22
0
lisp_object* LF_cdr(lisp_object* obj)
{
  return get_car(get_cdr(obj));
}