lisp処理系ぽいものを書く(その6くらい)

実装言語を何故かD言語からC言語へ移行してみました。かなりアッサリできました。いかに俺がD言語の機能を有効に利用していなかったかの証拠だと思った。
記号表は適当にオープンなハッシュテーブルで書いてみました。ハッシュ関数とか超適当。GCのタイミングはプログラムの終了時です。節子それGCやない、OSのメモリ管理や。
あとまあset!とlambdaをごにょごにょしてクロージャとか書けるようにしてみた。lambdaの実装がものごっそ適当。

> (define make-counter (lambda () ((lambda (c) (lambda () (set! c (+ c 1)) c)) 0)))
#closure
> (define c1 (make-counter))
#closure
> (define c2 (make-counter))
#closure
> (c1)
1
> (c1)
2
> (c1)
3
> (c2)
1
> (c2)
2
> (c1)
4
> ((lambda (f x) (f f x)) (lambda (f x) (if (zero? x) 1 (* x (f f (- x 1))))) (+ 1 2 3))
720
> Good-bye

一応アーカイブ。
http://konbu.s13.xrea.com/lib/scm/istsp-c-20070929.tar.bz2
以下にソースコードはっつけとく。1000行くらい。
istsp.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "istsp.h"

Cell newCell(Type t)
{
  Cell new = (Cell)malloc(sizeof(struct cell));
  new->_type = t;
  return new;
}
Cell charCell(char ch)
{
  Cell c = newCell(T_CHAR);
  chvalue(c) = ch;
  return c;
}
Cell stringCell(char* str)
{
  Cell c = newCell(T_STRING);
  strvalue(c) = (char*)malloc(sizeof(char)*strlen(str));
  strcpy(strvalue(c), str);
  return c;
}
Cell intCell(int val)
{
  Cell c = newCell(T_INTEGER);
  ivalue(c) = val;
  return c;
}
Cell pairCell(Cell a, Cell d)
{
  Cell cons = newCell(T_PAIR);
  car(cons) = a;
  cdr(cons) = d;
  return cons;
}
Cell procCell(opType proc)
{
  Cell c = newCell(T_PROC);
  procvalue(c) = proc;
  return c;
}
Cell syntaxCell(opType syntax)
{
  Cell c = newCell(T_SYNTAX);
  procvalue(c) = syntax;
  return c;
}
Cell symbolCell(char* symbol)
{
  Cell c = newCell(T_SYMBOL);
  symbolname(c) = (char*)malloc(sizeof(char)*strlen(symbol));
  strcpy(symbolname(c), symbol);
  return c;
}
Cell lambdaCell(Cell param, Cell exp)
{
  Cell c = newCell(T_LAMBDA);
  lambdaparam(c) = param;
  lambdaexp(c) = exp;
  return c;
}
void setString(Cell c, char* str)
{
  strvalue(c) = (char*)malloc(sizeof(char)*strlen(str));
  strcpy(strvalue(c), str);
}

Cell apply(Cell c)
{
  switch(type(c)){
    case T_SYMBOL:
      return getVar(symbolname(c));
    case T_PAIR:
      return evalExp(c);
    default:
      return c;
  }
  return c;
}
Cell clone(Cell src)
{
  Cell new = newCell(type(src));
  set(new, src);
  return new;
}
Cell cloneTree(Cell src)
{
  if(isPair(src)){
    return pairCell(cloneTree(car(src)), cloneTree(cdr(src)));
  }
  else if(isNone(src)){
    return src;
  }
  else{
    Cell new = newCell(type(src));
    set(new, src);
    return new;
  }
}
Cell cloneSymbolTree(Cell src)
{
  if(isPair(src)){
    return pairCell(cloneSymbolTree(car(src)), cloneSymbolTree(cdr(src)));
  }
  else if(isSymbol(src)){
    Cell new = newCell(type(src));
    set(new, src);
    return new;
  }
  else{
    return src;
  }
}
void set(Cell src, Cell dst)
{
  type(src) = type(dst);
  switch(type(src)){
    case T_CHAR:
      chvalue(src) = chvalue(dst);
      break;
    case T_STRING:
      setString(src, strvalue(dst));
      break;
    case T_INTEGER:
      ivalue(src) = ivalue(dst);
      break;
    case T_PAIR:
      car(src) = car(dst);
      cdr(src) = cdr(dst);
      break;
    case T_PROC:
      procvalue(src) = procvalue(dst);
      break;
    case T_SYNTAX:
      procvalue(src) = procvalue(dst);
      break;
    case T_LAMBDA:
      car(src) = car(dst);
      cdr(src) = cdr(dst);
      break;
    case T_SYMBOL:
      setString(src, strvalue(dst));
      break;
    default:
      setParseError("in set operation");
      break;
  }
}

Cell evalExp(Cell exp)
{
  Cell params, exps;
  Cell proc = apply(car(exp));
  Cell args = cdr(exp);
  opType operator;
  switch(type(proc)){
    case T_PROC:
      operator = procvalue(proc);
      args = applyList(args);
      break;
    case T_SYNTAX:
      operator = syntaxvalue(proc);
      break;
    case T_LAMBDA:
      params = lambdaparam(proc);
      exps = lambdaexp(proc);
      if(length(args) != length(params)){
        setParseError("wrong number arguments");
        return UNDEF;
      }
      args = applyList(args);
      args = cloneTree(args);
      exps = cloneSymbolTree(exps);
      letParam(exps, params, args);
      exps = pairCell(symbolCell("begin"), exps);
      set(exp, exps);
      return evalExp(exp);
    default:
      setParseError("not proc");
      return UNDEF;
  }
  pushArg(args);
  operator();
  return getReturn();
}
void letParam(Cell exp, Cell dummyParams, Cell realParams)
{
  if(nullp(exp)) return;
  else if(isPair(exp)){
    Cell carCell = car(exp);
    Cell cdrCell = cdr(exp);
    if(isPair(carCell)){
      letParam(carCell, dummyParams, realParams);
    }
    else if(isSymbol(carCell)){
      Cell find = findParam(carCell, dummyParams, realParams);
      if(find!=UNDEF){
        car(exp) = find;
      }
    }
    if(isPair(cdrCell)){
      letParam(cdrCell, dummyParams, realParams);
    }
    else if(isSymbol(cdrCell)){
      Cell find = findParam(cdrCell, dummyParams, realParams);
      if(find!=UNDEF){
        cdr(exp) = find;
      }
    }
  }
}
Cell findParam(Cell exp, Cell dummyParams, Cell realParams)
{
  char *var = symbolname(exp);
  while(!nullp(dummyParams)){
    char *key = strvalue(car(dummyParams));
    if(strcmp(var, key)==0){
      return car(realParams);
    }
    dummyParams = cdr(dummyParams);
    realParams = cdr(realParams);
  }
  return UNDEF;
}

int isdigitstr(char* str)
{
  int i;
  for(i=0;i<strlen(str);++i){
    if(!isdigit(str[i])){
      if(strlen(str) < 2 || i!=0 ||
          (str[0] != '-' && str[0] != '+')) return 0;
    }
  }
  return 1;
}
int nullp(Cell c)
{
  return c==NIL?1:0;
}
int truep(Cell c)
{
  return c==T?1:0;
}
int notp(Cell c)
{
  return c==F?1:0;
}
int eofp(Cell c)
{
  return c==EOFobj?1:0;
}
int zerop(Cell c)
{
  return ivalue(c)==0?1:0;
}
int length(Cell ls)
{
  int length = 0;
  for(;!nullp(ls);ls=cdr(ls)){
    ++length;
  }
  return length;
}
Cell setAppendCell(Cell ls, Cell c)
{
  if(nullp(ls)){
    if(nullp(c)){
      return ls;
    }
    else{
      return pairCell(c, NIL);
    }
  }
  Cell cdr = ls;
  while(!nullp(cdr(cdr))){
    cdr = cdr(cdr);
  }
  cdr(cdr) = pairCell(c, NIL);
  return ls;
}
Cell setAppendList(Cell ls, Cell append)
{
  if(nullp(ls)){
    return append;
  }
  Cell cdr = ls;
  while(!nullp(cdr(cdr))){
    cdr = cdr(cdr);
  }
  cdr(cdr) = append;
  return ls;
}
Cell reverseList(Cell ls)
{
  Cell reverse = NIL;
  for(;!nullp(ls);ls=cdr(ls)){
    reverse = pairCell(car(ls), reverse);
  }
  return reverse;
}
Cell applyList(Cell ls)
{
  if(nullp(ls)) return ls;
  Cell applyCar = apply(car(ls));
  return pairCell(applyCar, applyList(cdr(ls)));
}
void printCons(Cell c)
{
  printf("(");
  while(isPair(cdr(c))){
    printCell(car(c));
    printf(" ");
    c = cdr(c);
  }
  printCell(car(c));
  if(!nullp(cdr(c))){
    printf(" . ");
    printCell(cdr(c));
  }
  printf(")");
}
void printLineCell(Cell c)
{
  printCell(c);
  putchar('\n');
}
void printCell(Cell c)
{
  switch(type(c)){
    case T_NONE:
      if(c==T){
        printf("#t");
      }
      else if(c==F){
        printf("#f");
      }
      else if(c==NIL){
        printf("()");
      }
      else if(c==UNDEF){
        printf("#undef");
      }
      else if(c==EOFobj){
        printf("#<eof>");
      }
      else{
        setParseError("unknown cell");
      }
      break;
    case T_CHAR:
      printf("#\\%c", chvalue(c));
      break;
    case T_STRING:
      printf("\"%s\"", strvalue(c));
      break;
    case T_INTEGER:
      printf("%d", ivalue(c));
      break;
    case T_PROC:
      printf("#proc");
      break;
    case T_SYNTAX:
      printf("#syntax");
      break;
    case T_SYMBOL:
      printf("%s", symbolname(c));
      break;
    case T_PAIR:
      printCons(c);
      break;
    case T_LAMBDA:
      printf("#closure");
      break;
    default:
      fputs("\nunknown cell", stderr);
      break;
  }
#ifdef DEBUG
  printf("<%p>", c);
#endif
}
char* readTokenInDQuot(char* buf, int len)
{
  int prev = EOF;
  char *strp = buf;
  *strp = '"';
  for(++strp;(strp-buf)<len-1;++strp){
    int c = getchar();
    switch(c){
      case '"':
        if(prev!='\\'){
          *strp = c;
          goto BreakLoop;
        }
        else{
          *strp = c;
          break;
        }
      case EOF:
        setEOFException("End Of File");
        return NULL;
      default:
        *strp = c;
        prev = c;
        break;
    }
  }
BreakLoop:
  *strp = '\0';
  return buf;
}
char* readToken(char *buf, int len)
{
  char *token = buf;
  for(;(token-buf)<len-1;){
    int c = getchar();
    switch(c){
      case '(':
      case ')':
      case '\'':
        if(token-buf > 0){
          ungetc(c, stdin);
        }
        else{
          *token = c;
          ++token;
        }
        *token = '\0';
        return buf;
      case '"':
        if(token-buf > 0){
          ungetc(c, stdin);
          *token = '\0';
          return buf;
        }
        return readTokenInDQuot(buf, len);
      case ' ':
      case '\t':
      case '\n':
        if(token-buf > 0){
          *token = '\0';
          return buf;
        }
        break;
      case EOF:
        setEOFException("Enf Of File");
        return NULL;
      default:
        *token = c;
        ++token;
        break;
    }
  }
  *token = '\0';
  return buf;
}
Cell readList()
{
  Cell list = NIL;
  char c;
  char buf[LINESIZE];
  while(1){
    Cell exp;
    c = getchar();
    switch(c){
      case ')':
        return list;
      case '.':
        exp = readElem();
        list = setAppendList(list, exp);
        readToken(buf, sizeof(buf));
        if(strcmp(buf, ")")!=0){
          setParseError("unknown token after '.'");
          return NULL;
        }
        return list;
      case EOF:
        setEOFException("EOF");
        return NULL;
      default:
        ungetc(c, stdin);
        exp = readElem();
        list = setAppendCell(list, exp);
        break;
    }
  }
  return list;
}
Cell readQuot()
{
  Cell quot = NIL;
  quot = setAppendCell(quot, symbolCell("quote"));
  quot = setAppendCell(quot, readElem());
  return quot;
}
Cell tokenToCell(char* token)
{
  if(isdigitstr(token)){
    int digit = atoi(token);
    return intCell(digit);
  }
  else if(token[0] == '"'){
    return stringCell(token+1);
  }
  else if(token[0] == '#'){
    if(token[1] == '\\' && strlen(token)==3){
      return charCell(token[2]);
    }
    else{
      return symbolCell(token);
    }
  }
  else{
    return symbolCell(token);
  }
}
Cell readElem()
{
  Cell elem;
  char buf[LINESIZE];
  char* token = readToken(buf, sizeof(buf));
  if(token==NULL){
    elem = NULL;
  }
  else if(token[0]=='('){
    elem = readList();
  }
  else if(token[0]=='\''){
    elem = readQuot();
  }
  else{
    elem = tokenToCell(token);
  }

  if(elem==NULL){
    int err = errorNo;
    clearError();
    if(err==EOF_ERR){
      return EOFobj;
    }
    else{
      return NULL;
    }
  }
  return elem;
}

int hash(char* key)
{
  int val = 0;
  for(;*key!='\0';++key){
    val = val*256 + *key;
  }
  return val;
}
Cell getVar(char* name)
{
  int key = hash(name)%ENVSIZE;
  Cell chain = env[key];
  if(chain==NULL || nullp(chain)) return UNDEF;
  while(strcmp(name, strvalue(caar(chain)))!=0){
    if(nullp(cdr(chain))){
      return UNDEF;
    }
    chain = cdr(chain);
  }
  return cdar(chain);
}
void setVar(char* name, Cell c)
{
  int key = hash(name)%ENVSIZE;
  Cell nameCell = stringCell(name);
  Cell chain = env[key], entry;
  if(env[key]==NULL){
    chain = env[key] = NIL;
  }
  while(!nullp(chain) && strcmp(name, strvalue(caar(chain)))!=0){
    chain = cdr(chain);
  }
  entry = pairCell(nameCell, c);
  if(!nullp(chain)){
    car(chain) = entry;
  }
  else{
    env[key] = pairCell(entry, env[key]);
  }
}
Cell popArg()
{
  Cell c = car(argsReg);
  argsReg = cdr(argsReg);
  return c;
}
void pushArg(Cell c)
{
  argsReg = pairCell(c, argsReg);
}
void dupArg()
{
  Cell c = popArg();
  pushArg(c);
  pushArg(c);
}
void exchArg()
{
  Cell c1 = popArg();
  Cell c2 = popArg();
  pushArg(c1);
  pushArg(c2);
}
void clearArgs()
{
  argsReg = NIL;
}
void callProc(char* name)
{
  Cell proc = getVar(name);
  if(isProc(proc)){
    opType op = procvalue(proc);
    op();
  }
  else{
    setParseError("unknown proc");
  }
}
Cell getReturn()
{
  return car(retReg);
}
void setReturn(Cell c)
{
  retReg = pairCell(c, NIL);
}
void setParseError(char* str)
{
  errorNo = PARSE_ERR;
  strcpy(errorString, str);
}
void setEOFException(char* str)
{
  errorNo = EOF_ERR;
  strcpy(errorString, str);
}
int getErrorNo()
{
  return errorNo;
}
void clearError()
{
  errorNo = NONE_ERR;
  errorString[0] = '\0';
}

void init()
{
  NIL = pairCell(NIL, NIL);
  type(NIL) = T_NONE;

  T = pairCell(T, T);
  type(T) = T_NONE;

  F = pairCell(F, F);
  type(F) = T_NONE;

  UNDEF = pairCell(UNDEF, UNDEF);
  type(UNDEF) = T_NONE;

  EOFobj = pairCell(EOFobj, EOFobj);
  EOFobj = T_NONE;

  argsReg = retReg = NIL;

  memset(env, 0, ENVSIZE);


  setVar("nil", NIL);
  setVar("#t", T);
  setVar("#f", F);

  setVar("null?",   procCell(op_nullp));
  setVar("not",     procCell(op_notp));
  setVar("eof?",    procCell(op_eofp));
  setVar("zero?",   procCell(op_zerop));
  setVar("=",       procCell(op_eqdigitp));
  setVar("car",     procCell(op_car));
  setVar("cdr",     procCell(op_cdr));
  setVar("cons",    procCell(op_cons));
  setVar("list",    procCell(op_list));
  setVar("+",       procCell(op_add));
  setVar("-",       procCell(op_sub));
  setVar("*",       procCell(op_mul));
  setVar("/",       procCell(op_div));
  setVar("append",  procCell(op_append));
  setVar("reverse", procCell(op_reverse));
  setVar("eval",    procCell(op_eval));
  setVar("read",    procCell(op_read));
  setVar("print",   procCell(op_print));

  setVar("define",  syntaxCell(syntax_define));
  setVar("if",      syntaxCell(syntax_ifelse));
  setVar("lambda",  syntaxCell(syntax_lambda));
  setVar("quote",   syntaxCell(syntax_quote));
  setVar("set!",    syntaxCell(syntax_set));
  setVar("begin",   syntaxCell(syntax_begin));
}
void op_unknown()
{
  setReturn(UNDEF);
}
void op_nullp()
{
  Cell args = popArg();
  if(nullp(car(args))){
    setReturn(T);
  }
  else{
    setReturn(F);
  }
}
void op_notp()
{
  Cell args = popArg();
  if(notp(car(args))){
    setReturn(T);
  }
  else{
    setReturn(F);
  }
}
void op_eofp()
{
  Cell args = popArg();
  if(eofp(car(args))){
    setReturn(T);
  }
  else{
    setReturn(F);
  }
}
void op_zerop()
{
  Cell args = popArg();
  if(zerop(car(args))){
    setReturn(T);
  }
  else{
    setReturn(F);
  }
}
void op_eqdigitp()
{
  Cell args = popArg();
  Cell c1 = car(args);
  Cell c2 = cadr(args);
  int i1 = ivalue(apply(c1));
  int i2 = ivalue(apply(c2));
  if(i1==i2){
    setReturn(T);
  }
  else{
    setReturn(F);
  }
}
void op_car()
{
  Cell args = popArg();
  Cell c1 = car(args);
  setReturn(car(c1));
}
void op_cdr()
{
  Cell args = popArg();
  Cell c1 = car(args);
  setReturn(cdr(c1));
}
void op_cons()
{
  Cell args = popArg();
  Cell c1 = car(args);
  Cell c2 = cadr(args);
  setReturn(pairCell(c1, c2));
}
void op_list()
{
  Cell args = popArg();
  setReturn(args);
}
void op_add()
{
  Cell args = popArg();
  int ans = 0;
  while(args != NIL){
    ans += ivalue(car(args));
    args = cdr(args);
  }
  setReturn(intCell(ans));
}
void op_mul()
{
  Cell args = popArg();
  int ans = 1;
  while(args != NIL){
    ans *= ivalue(car(args));
    args = cdr(args);
  }
  setReturn(intCell(ans));
}
void op_sub()
{
  Cell args = popArg();
  Cell c1 = car(args);
  Cell list = cdr(args);
  int ans = ivalue(c1);
  while(list != NIL){
    ans -= ivalue(car(list));
    list = cdr(list);
  }
  setReturn(intCell(ans));
}
void op_div()
{
  Cell args = popArg();
  Cell c1 = car(args);
  Cell list = cdr(args);
  int ans = ivalue(c1);
  while(list != NIL){
    ans /= ivalue(car(list));
    list = cdr(list);
  }
  setReturn(intCell(ans));
}
void op_append()
{
  Cell args = popArg();
  Cell c1 = car(args);
  Cell c2 = cadr(args);
  Cell result = clone(c1);
  setReturn(setAppendList(result, c2));
}
void op_reverse()
{
  Cell args = popArg();
  Cell reverse = reverseList(args);
  setReturn(reverse);
}
void op_read()
{
  setReturn(readElem());
}
void op_eval()
{
  Cell args = popArg();
  setReturn(apply(car(args)));
  if(errorNo==PARSE_ERR){
    fprintf(stderr, "%s\n", errorString);
    setReturn(UNDEF);
  }
}
void op_print()
{
  Cell args = popArg();
  for(;!nullp(args);args=cdr(args)){
    Cell c = car(args);
    if(isString(c)){
      fputs(strvalue(c), stdout);
    }
    else{
      printCell(c);
    }
  }
  puts("");
  setReturn(UNDEF);
}

void syntax_define()
{
  Cell args = popArg();
  Cell symbol = car(args);
  Cell obj = cadr(args);
  obj = apply(obj);
  setVar(symbolname(symbol), obj);
  setReturn(obj);
}
void syntax_ifelse()
{
  Cell args = popArg();
  Cell cond = car(args);
  Cell tpart = cadr(args);
  Cell fpart = cddr(args);
  cond = apply(cond);
  if(truep(cond)){
    tpart = apply(tpart);
    setReturn(tpart);
  }
  else{
    if(nullp(fpart)){
      setReturn(UNDEF);
    }
    else{
      fpart = apply(car(fpart));
      setReturn(fpart);
    }
  }
}
void syntax_lambda()
{
  Cell args = popArg();
  Cell params = car(args);
  Cell exps = cdr(args);
  Cell lambda = lambdaCell(params, exps);
  setReturn(lambda);
}
void syntax_quote()
{
  setReturn(car(popArg()));
}
void syntax_set()
{
  Cell args = popArg();
  Cell c1 = car(args);
  Cell c2 = cadr(args);
  Cell src = apply(c1);
  set(src, apply(c2));
  setReturn(src);
}
void syntax_begin()
{
  Cell args = popArg();
  for(;!nullp(cdr(args));args=cdr(args)){
    apply(car(args));
  }
  setReturn(apply(car(args)));
}

int repl()
{
  while(1){
    Cell ret;
    fputs("> ", stderr);
    clearArgs();
    callProc("read");
    ret = getReturn();
    if(ret==EOFobj) break;
    pushArg(pairCell(ret, NIL));
    dupArg();
    callProc("eof?");
    ret = getReturn();
    if(truep(ret)) break;
    callProc("eval");
    printLineCell(getReturn());
  }
  fputs("Good-bye\n", stdout);
  return 0;
}
int main(int argc, char *argv[])
{
  init();
  repl();
  return 0;
}

istsp.h

typedef void (*opType)();
typedef enum type{
  T_NONE,
  T_CHAR,
  T_STRING,
  T_INTEGER,
  T_PAIR,
  T_PROC,
  T_SYNTAX,
  T_SYMBOL,
  T_LAMBDA,
} Type;
struct cell;
typedef struct cell *Cell;
typedef union cellUnion
{
  char    _char;
  char*   _string;
  int     _integer;
  struct{
    Cell  _car;
    Cell  _cdr;
  }       _cons;
  opType  _proc;
} CellUnion;
struct cell{
  Type _type;
  CellUnion _object;
};

#define type(p)         ((p)->_type)
#define car(p)          ((p)->_object._cons._car)
#define cdr(p)          ((p)->_object._cons._cdr)
#define caar(p)         car(car(p))
#define cadr(p)         car(cdr(p))
#define cdar(p)         cdr(car(p))
#define cddr(p)         cdr(cdr(p))
#define cadar(p)        car(cdr(car(p)))
#define caddr(p)        car(cdr(cdr(p)))
#define cadaar(p)       car(cdr(car(car(p))))
#define cadddr(p)       car(cdr(cdr(cdr(p))))
#define cddddr(p)       cdr(cdr(cdr(cdr(p))))

#define chvalue(p)      ((p)->_object._char)
#define strvalue(p)     ((p)->_object._string)
#define ivalue(p)       ((p)->_object._integer)
#define procvalue(p)    ((p)->_object._proc)
#define syntaxvalue(p)  ((p)->_object._proc)
#define symbolname(p)   strvalue(p)
#define lambdaparam(p)  car(p)
#define lambdaexp(p)    cdr(p)

Cell newCell(Type t);

#define isNone(p)       ((p)->_type==T_NONE)
#define isChar(p)       ((p)->_type==T_CHAR)
#define isString(p)     ((p)->_type==T_STRING)
#define isInteger(p)    ((p)->_type==T_INTEGER)
#define isPair(p)       ((p)->_type==T_PAIR)
#define isSymbol(p)     ((p)->_type==T_SYMBOL)
#define isProc(p)       ((p)->_type==T_PROC)
#define isSyntax(p)     ((p)->_type==T_SYNTAX)
#define isLambda(p)     ((p)->_type==T_LAMBDA)
void setString(Cell c, char* str);

Cell apply(Cell c);
Cell clone(Cell c);
void set(Cell src, Cell dst);

Cell charCell(char ch);
Cell stringCell(char* str);
Cell intCell(int val);
Cell pairCell(Cell a, Cell d);
Cell procCell(opType proc);
Cell syntaxCell(opType syn);
Cell symbolCell(char* name);
Cell lambdaCell(Cell param, Cell exp);

int isdigitstr(char* str);
int nullp(Cell c);
int truep(Cell c);
int notp(Cell c);
int eofp(Cell c);
int zerop(Cell c);
int eqdigitp(Cell c);
int length(Cell ls);
Cell setAppendCell(Cell ls, Cell c);
Cell setAppendList(Cell ls, Cell append);
Cell reverseList(Cell ls);
Cell applyList(Cell ls);

void printPair(Cell c);
void printCell(Cell c);
void printLineCell(Cell c);
char* readTokenInDQuot();
char* readToken();
Cell readList();
Cell readQuot();
Cell tokenToCell();
Cell readElem();

Cell evalExp(Cell exp);
void letParam(Cell exp, Cell dummyParams, Cell realParams);
Cell findParam(Cell exp, Cell dummyParams, Cell realParams);

Cell T, F, NIL, UNDEF, EOFobj;

Cell argsReg;
Cell retReg;
#define ENVSIZE 30000
Cell env[ENVSIZE];
#define LINESIZE 1024
char errorString[LINESIZE];
int errorNo = 0;
enum ErrorNo{
  NONE_ERR,
  PARSE_ERR,
  EOF_ERR,
};
//Cell[char[]] env;
//Cell[char[]] letenv;

void init();
int hash(char* key);
Cell getVar(char* name);
void setVar(char* name, Cell c);
Cell popArg();
void pushArg(Cell c);
void dupArg();
void exchArg();
void clearArgs();
void callProc(char* name);
Cell getReturn();
void setReturn(Cell c);
void setParseError(char* errorStr);
void setEOFException(char* str);
void clearError();

void op_nullp();
void op_notp();
void op_eofp();
void op_zerop();
void op_eqdigitp();
void op_car();
void op_cdr();
void op_cons();
void op_list();
void op_add();
void op_sub();
void op_mul();
void op_div();
void op_append();
void op_reverse();
void op_eval();
void op_read();
void op_print();
void syntax_define();
void syntax_ifelse();
void syntax_lambda();
void syntax_quote();
void syntax_set();
void syntax_begin();

int repl();

test