2015年4月19日日曜日

開発環境

Schemeの処理系(解釈系、評価機、レジスタ計算機を翻訳した命令列中心のより、もう少しC言語の特性を使った書き方をしたもの(label, gotoではなく、関数を呼び出すとか))を少しずつ書き進めてめていくことに。

GLibのHashTableを利用して、データ主導で構文振り分けをするように変更とcond構文の追加。(else節についてはどう実装するか、まだ迷い中。。)

データ主導にして加法的になったから、今後新しい構文を追加してくのが楽になったかも。

参考書籍等

kscheme

コード(BBEdit, Emacs)

#pragma once

void ev_application();
#pragma once

void apply_dispatch();
#pragma once
#include "data.h"

extern const data_s assignment_data;
void assignment_print(FILE *stream, data_s in);

void ev_assignment();
#pragma once
#include "data.h"

extern const data_s begin_data;
void begin_print(FILE *stream, data_s in);
void ev_begin();  
#pragma once
#include "data.h"

extern const data_s true_data;
extern const data_s false_data;

void boolean_print(FILE *stream, data_s in);

bool is_true(data_s in);
#pragma once
#include "data.h"

extern const data_s cond_data;

void cond_print(FILE *stream, data_s in);

void ev_cond();
#pragma once
#include <glib.h>
#include <gmp.h>
#include <stdbool.h>
#include <stdarg.h>

typedef enum {
  /* 基本型 */
  PAIR,
  EMPTY,
  Z,
  Q,
  R,
  SYMBOL,
  CHAR,
  STRING,
  BOOLEAN,
  /* 接続 */
  FN,
  /* primitive_procedure */
  PRIMITIVE_PROCEDURE,
  PROCEDURE,
  /* syntax */
  QUOTE,
  ASSIGNMENT,
  DEFINITION,
  IF,
  LAMBDA,
  BEGIN,
  COND,
  QUASIQUOTE,
  /* 初期化 */
  NONE,
  /* undefined */
  UNDEF,
  /* error */
  ERROR,  
} data_type;

typedef void (*a_fn_type)(void);
typedef union {
  int index;
  mpz_t z;
  mpq_t q;
  mpf_t r;
  char *symbol;
  char ch;
  char *str;
  bool bln;
  a_fn_type fn;
  char *proc_name;
} data_u;

typedef struct {
  data_type type;
  data_u data;
} data_s;

extern GHashTable *data_s_new_fns;
typedef data_s (*data_s_new_fn_type)(char *in);
void check_data_s_new_fn_type(data_s_new_fn_type fn);
#define data_s_new_hash_add(type, fn)                                          \
  {                                                                            \
    check_data_s_new_fn_type(fn);                                              \
    g_hash_table_insert(data_s_new_fns, GINT_TO_POINTER(type), fn);            \
  }
data_s data_s_new(data_type type, char *in);

extern GHashTable *data_s_copy_fns;
typedef data_s (*data_s_copy_fn_type)(data_s in);
void check_data_s_copy_fn_type(data_s_copy_fn_type cf);
#define data_s_copy_hash_add(type, fn)                                         \
  {                                                                            \
    check_data_s_copy_fn_type(fn);                                             \
    g_hash_table_insert(data_s_copy_fns, GINT_TO_POINTER(type), fn);           \
  }
data_s data_s_copy(data_s in);

extern GHashTable *data_s_free_fns;
typedef void (*data_s_free_fn_type)(data_s in);
void check_data_s_free_fn_type(data_s_free_fn_type ff);
#define data_s_free_hash_add(type, fn)                                         \
  {                                                                            \
    check_data_s_free_fn_type(fn);                                             \
    g_hash_table_insert(data_s_free_fns, GINT_TO_POINTER(type), fn);           \
  }
data_s data_s_free(data_s in);

#include <stdio.h>
extern GHashTable *data_s_print_fns;
typedef void (*data_s_print_fn_type)(FILE *stream, data_s in);
void check_data_s_print_fn_type(data_s_print_fn_type fn);
#define data_s_print_hash_add(type, fn)                                        \
  {                                                                            \
    check_data_s_print_fn_type(fn);                                            \
    g_hash_table_insert(data_s_print_fns, GINT_TO_POINTER(type), fn);          \
  }
void data_s_print(FILE *stream, data_s in);

void data_s_fns_init();
#pragma once
#include "data.h"

extern const data_s definition_data;
void definition_print(FILE *stream, data_s in);

void ev_definition();
#pragma once
#include "data.h"

extern const data_s empty_data;

void empty_print(FILE *stream, data_s in);

data_s is_null(data_s in);
#pragma once
#include "data.h"

data_s lookup_variable_value(data_s expr, data_s env);
data_s set_variable_value(data_s var, data_s val, data_s env);
data_s define_variable(data_s var, data_s val, data_s env);

data_s extend_environment(data_s vars, data_s vals, data_s base_env);
extern data_s global_environment;

data_s setup_environment();
#pragma once
#include "data.h"

extern const data_s error_data;

void error_print(FILE *stream, data_s in);

void ev_error();
#pragma once
#include "data.h"
#include <glib.h>

extern data_s expr, env, val, cont, proc, argl, unev;

extern GHashTable *eval_fns;
typedef void (*eval_fn_type)(void);
void check_eval_fn_type(eval_fn_type ef);
#define eval_hash_add(type, fn)                                                \
  {                                                                            \
    check_eval_fn_type(fn);                                                    \
    g_hash_table_insert(eval_fns, GINT_TO_POINTER(type), fn);                  \
  }

extern int eval_flag;
void eval_dispatch();

void eval_fns_init();
#pragma once
#include "data.h"
#include <stdbool.h>

bool is_self_evaluating(data_s in);
bool is_variable(data_s in);

bool is_tagged_list(data_s in, char *tag);
bool is_quoted(data_s in);
data_s text_of_quotation(data_s in);

bool is_assignment(data_s in);
data_s assignment_variable(data_s in);
data_s assignment_value(data_s in);

bool is_definition(data_s in);
data_s definition_variable(data_s in);
data_s definition_value(data_s in);

bool is_lambda(data_s in);
data_s lambda_parameters(data_s in);
data_s lambda_body(data_s in);
data_s make_lambda(data_s parameters, data_s body);

bool is_if(data_s in);
data_s if_predicate(data_s in);
data_s if_consequent(data_s in);
data_s if_alternative(data_s in);

data_s make_if(data_s predicate, data_s consequent, data_s alternative);

bool is_begin(data_s in);
data_s begin_actions(data_s in);
bool is_last_expr(data_s in);
data_s first_expr(data_s in);
data_s rest_exprs(data_s in);
data_s sequence2expr(data_s in);
data_s make_begin(data_s in);

bool is_application(data_s in);
data_s operator(data_s in);
data_s operands(data_s in);
bool no_operands(data_s in);
data_s first_operand(data_s in);
data_s rest_operands(data_s in);

bool is_cond(data_s in);
data_s cond_clauses(data_s in);
bool is_cond_else_clause(data_s in);
data_s cond_predicate(data_s in);
data_s cond_actions(data_s in);
data_s expand_clauses(data_s in);
#pragma once

void begin_garbage_collection();
#pragma once
#include "data.h"

extern const data_s if_data;
void if_print(FILE *stream, data_s in);

void ev_if();

extern data_s if_sym;
data_s make_if(data_s in1, data_s in2, data_s in3);
#pragma once
#include "data.h"

data_s kread(FILE *in);
#pragma once
#include "data.h"

extern const data_s lambda_data;

void lambda_print(FILE *stream, data_s in);
void ev_lambda();

extern data_s lambda_sym;
data_s make_lambda(data_s in1, data_s in2);
#pragma once
#include "data.h"

extern const int memory_size;
extern data_s *cars;
extern data_s *cdrs;
extern char *markers;
extern int marker_count;
extern data_s root;

data_s car(data_s in);
data_s cdr(data_s in);
data_s set_car(data_s in1, data_s in2);
data_s set_cdr(data_s in1, data_s in2);
extern int marker_count;
extern int free_index;
data_s cons(data_s in1, data_s in2);

data_s set(data_s *in1, data_s in2);
#include <stdarg.h>
data_s list(int args, ...);
data_s append(data_s in1, data_s in2);

data_s caar(data_s in);
data_s cadr(data_s in);
data_s cdar(data_s in);
data_s cddr(data_s in);
data_s caaar(data_s in);
data_s caadr(data_s in);
data_s cadar(data_s in);
data_s caddr(data_s in);
data_s cdaar(data_s in);
data_s cdadr(data_s in);
data_s cddar(data_s in);
data_s cdddr(data_s in);
data_s caaaar(data_s in);
data_s caaadr(data_s in);
data_s caadar(data_s in);
data_s caaddr(data_s in);
data_s cadaar(data_s in);
data_s cadadr(data_s in);
data_s caddar(data_s in);
data_s cadddr(data_s in);
data_s cdaaar(data_s in);
data_s cdaadr(data_s in);
data_s cdadar(data_s in);
data_s cdaddr(data_s in);
data_s cddaar(data_s in);
data_s cddadr(data_s in);
data_s cdddar(data_s in);
data_s cddddr(data_s in);
#pragma once
#include "data.h"

const data_s none_data;
#pragma once
#include "data.h"

data_s is_number(data_s in);
#pragma once
#include "data.h"

data_s number_q_new(char *in);
data_s number_q_copy(data_s in);
void number_q_free(data_s in);
void number_q_print(FILE *stream, data_s in);
bool number_q_eq(data_s in1, data_s in2);
#pragma once
#include "data.h"

data_s number_r_new(char *in);
data_s number_r_copy(data_s in);
void number_r_free(data_s in);
void number_r_print(FILE *stream, data_s in);
bool number_r_eq(data_s in1, data_s in2);
#pragma once
#include "data.h"

data_s number_z_new(char *in);
data_s number_z_copy(data_s in);
void number_z_free(data_s in);
void number_z_print(FILE *stream, data_s in);

bool number_z_eq(data_s in1, data_s in2);
#pragma once
#include "data.h"

/* void pair_free(data_s in); */
void pair_print(FILE *stream, data_s in);

bool pair_eq(data_s in1, data_s in2);

data_s is_pair(data_s in);
#pragma once
#include "data.h"

data_s prim_car(data_s in);
data_s prim_cdr(data_s in);
data_s prim_set_car(data_s in);
data_s prim_set_cdr(data_s in);
data_s prim_cons(data_s in);

/* data_s prim_set(data_s in); */

data_s prim_list(data_s in);
data_s prim_append(data_s in);

data_s prim_caar(data_s in);
data_s prim_cadr(data_s in);
data_s prim_cdar(data_s in);
data_s prim_cddr(data_s in);
data_s prim_caaar(data_s in);
data_s prim_caadr(data_s in);
data_s prim_cadar(data_s in);
data_s prim_caddr(data_s in);
data_s prim_cdaar(data_s in);
data_s prim_cdadr(data_s in);
data_s prim_cddar(data_s in);
data_s prim_cdddr(data_s in);
data_s prim_caaaar(data_s in);
data_s prim_caaadr(data_s in);
data_s prim_caadar(data_s in);
data_s prim_caaddr(data_s in);
data_s prim_cadaar(data_s in);
data_s prim_cadadr(data_s in);
data_s prim_caddar(data_s in);
data_s prim_cadddr(data_s in);
data_s prim_cdaaar(data_s in);
data_s prim_cdaadr(data_s in);
data_s prim_cdadar(data_s in);
data_s prim_cdaddr(data_s in);
data_s prim_cddaar(data_s in);
data_s prim_cddadr(data_s in);
data_s prim_cdddar(data_s in);
data_s prim_cddddr(data_s in);
#pragma once
#include "data.h"

data_s prim_number_add(data_s in);
data_s prim_number_sub(data_s in);
data_s prim_number_mul(data_s in);
data_s prim_number_div(data_s in);
data_s prim_number_eq(data_s in);
data_s prim_number_less_than(data_s in);
#pragma once
#include "data.h"

data_s primitive_procedure_new(char *in);
void primitive_procedure_print(FILE *stream, data_s in);

bool is_primitive_procedure(data_s in);

data_s apply_primitive_procedure(data_s in1, data_s in2);

void prim_proc_init();
#pragma once
#include "data.h"

void procedure_print(FILE *stream, data_s in);
bool is_procedure(data_s in);
data_s make_procedure(data_s param, data_s body, data_s env);
#pragma once
#include "data.h"

void quasiquote_print(FILE *stream, data_s in);

extern const data_s quasiquote_data;
#pragma once
#include "data.h"

void quote_print(FILE *stream, data_s in);
  
extern const data_s quote_data;
void ev_quoted();
#pragma once

void read_eval_print_loop();
#pragma once
#include "data.h"

bool is_self_evaluating(data_s in);

void ev_self_eval();
#pragma once

void ev_sequence();
#pragma once
#include "data.h"

extern data_s stack;
void save(data_s in);
data_s restore();
void initialize_stack();
void print_statistics();
#include <stdio.h>
#include <stdlib.h> //abort

/** Set this to \c 's' to stop the program on an error.
    Otherwise, functions return a value on failure.*/
char error_mode;

/** To where should I write errors? If this is \c NULL, write to \c stderr. */
FILE *error_log;

#define Stopif(assertion, error_action, ...) {              \
    if (assertion){                                         \
      fprintf(error_log ? error_log : stderr, __VA_ARGS__); \
      fprintf(error_log ? error_log : stderr, "\n");        \
      if (error_mode=='s') abort();                         \
      else {error_action;}                                  \
    }}
#pragma once
#include "data.h"

data_s string_new(char *in);
data_s string_copy(data_s in);
void string_free(data_s in);
void string_print(FILE *stream, data_s in);
#pragma once
#include "data.h"

extern GHashTable *obarray;

data_s symbol_new(char *in);
void symbol_print(FILE *stream, data_s in);

bool symbol_eq(data_s in1, data_s in2);
data_s is_symbol(data_s in);
#pragma once
#include "data.h"

extern const data_s undef;
void undef_print(FILE *stream, data_s in);
#pragma once
#include "data.h"

bool is_variable(data_s in);

void ev_variable();
#include "application.h"
#include "evaluator.h"
#include "list_operations.h"
#include "stack.h"

static void ev_appl_did_operator();
static void ev_appl_operand_loop();
static void ev_appl_accumulate_arg();
static void ev_appl_last_arg();
static void ev_appl_accum_last_arg();

void ev_application() {
  save(env);
  unev = data_s_free(unev);
  unev = cdr(expr);
  save(unev);
  expr = car(expr);
  eval_dispatch();
  ev_appl_did_operator();
}

#include "empty.h"
#include "apply.h"
static void ev_appl_did_operator() {
  /* printf("ev_appl_did_operator\n"); */
  data_s_free(unev);
  unev = restore();
  env = restore();
  argl = empty_data;
  proc = data_s_copy(val);
  if (unev.type == EMPTY)
    apply_dispatch();
  else {
    save(proc);
    ev_appl_operand_loop();
  }
}

static void ev_appl_operand_loop() {
  /* printf("ev_appl_operand_loop\n"); */
  save(argl);
  data_s_free(expr);
  expr = car(unev);
  if (cdr(unev).type == EMPTY) {
    ev_appl_last_arg();
  } else {
    save(env);
    save(unev);
    eval_dispatch();
    ev_appl_accumulate_arg();
  }
}

static void ev_appl_accumulate_arg() {
  /* printf("ev_appl_accumulate_arg\n"); */
  data_s_free(unev);
  unev = restore();
  env = restore();
  argl = restore();
  argl = append(argl, list(1, val));
  unev = cdr(unev);
  ev_appl_operand_loop();
}

static void ev_appl_last_arg() {
  /* printf("ev_appl_last_arg\n"); */
  eval_dispatch();
  ev_appl_accum_last_arg();
}

static void ev_appl_accum_last_arg() {
  /* printf("ev_appl_accum_last_arg\n"); */
  argl = restore();
  argl = append(argl, list(1, val));
  data_s_free(proc);
  proc = restore();
  apply_dispatch();
}
#include "apply.h"
#include "primitive_procedure.h"
#include "procedure.h"
#include "evaluator.h"

static void primitive_apply();
static void compound_apply();

void apply_dispatch() {
  /* printf("apply_dispatch\n"); */
  /* printf("proc: "); */
  /* data_s_print(stdout, proc); */
  /* printf("\n"); */
  /* printf("argl: "); */
  /* data_s_print(stdout, argl); */
  /* printf("\n"); */
  if (is_primitive_procedure(proc)) {
    primitive_apply();
  } else if (is_procedure(proc))
    compound_apply();
}

#include "stack.h"
static void primitive_apply() {
  data_s_free(val);
  val = apply_primitive_procedure(proc, argl);
}

#include "environment.h"
#include "sequence.h"
#include "list_operations.h"
#include "environment.h"
static void compound_apply() {
  /* printf("compound_apply\n"); */
  unev = data_s_free(unev);
  unev = car(proc);
  env = caddr(proc);
  env = extend_environment(unev, argl, env);
  unev = cadr(proc);
  ev_sequence();
}
#include "assignment.h"
#include "evaluator.h"
#include "list_operations.h"
#include "stack.h"

const data_s assignment_data = {.type = ASSIGNMENT};
void assignment_print(FILE *stream, data_s in) {
  fprintf(stream, "#<syntax set!>");
}

static void f() {}
static void ev_assignment1();
void ev_assignment() {
  unev = data_s_free(unev);
  unev = cadr(expr);
  save(unev);
  data_s t = caddr(expr);
  expr = data_s_free(expr);
  expr = t;
  save(env);
  /* save(cont);   */
  /* cont.data.fn = ev_assignment1;変更 */
  /* cont.data.fn = f; */
  eval_dispatch();
  ev_assignment1();
}
#include "environment.h"
static void ev_assignment1() {
  /* cont = restore(); */
  env = data_s_free(env);
  env = restore();
  unev = data_s_free(unev);
  unev = restore();
  set_variable_value(unev, val, env);
  /* cont.data.fn(); */
}
#include "begin.h"

const data_s begin_data = {.type=BEGIN};
void begin_print(FILE *stream, data_s in) {
  fprintf(stream, "#<syntax begin>");
}

#include "evaluator.h"
#include "list_operations.h"
#include "stack.h"
#include "sequence.h"
void ev_begin() {
  data_s_free(unev);
  unev = cdr(expr);
  ev_sequence();
}

#include "boolean.h"

const data_s true_data = {.type = BOOLEAN, .data.bln = true};
const data_s false_data = {.type = BOOLEAN, .data.bln = false};

void boolean_print(FILE *stream, data_s in) {
  if (in.data.bln == true)
    fprintf(stream, "#t");
  else {
    fprintf(stream, "#f");
  }
}

bool boolean_eq(data_s in1, data_s in2) { return in1.data.bln == in2.data.bln; }

bool is_true(data_s in) {
  return in.type != BOOLEAN || in.data.bln != false ? true : false;
}
#include "cond.h"

const data_s cond_data = {.type = COND};

void cond_print(FILE *stream, data_s in) { fprintf(stream, "#<syntax cond>"); }

#include "evaluator.h"
#include "list_operations.h"
#include "undef.h"
#include "if.h"
#include "symbol.h"
#include "begin.h"
#include "environment.h"
static data_s expand_clauses(data_s in) {
  if (in.type == EMPTY)
    return undef;
  data_s first = car(in);
  data_s rest = cdr(in);
  data_s t = cdr(first);
  if (t.type == EMPTY)
    return make_if(car(first), t, expand_clauses(rest));
  if (cdr(t).type == EMPTY)
    return make_if(car(first), car(t), expand_clauses(rest));
  return make_if(car(first), cons(begin_data, t), expand_clauses(rest));
}
static data_s cond2if(data_s in) { return expand_clauses(cdr(in)); }

void ev_cond() {
  expr = cond2if(expr);
  eval_flag = 1;
}
#include "data.h"
#include "list_operations.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>

GHashTable *data_s_new_fns;
void check_data_s_new_fn_type(data_s_new_fn_type fn) {}
data_s data_s_new(data_type type, char *in) {
  data_s_new_fn_type nf =
      g_hash_table_lookup(data_s_new_fns, GINT_TO_POINTER(type));
  return nf(in);
}

GHashTable *data_s_copy_fns;
void check_data_s_copy_fn_type(data_s_copy_fn_type cf) {}
data_s data_s_copy(data_s in) {
  data_s_copy_fn_type cf =
      g_hash_table_lookup(data_s_copy_fns, GINT_TO_POINTER(in.type));
  if (!cf)
    return in;
  else
    return cf(in);
}

#include "none.h"
GHashTable *data_s_free_fns;
void check_data_s_free_fn_type(data_s_free_fn_type ff) {}
data_s data_s_free(data_s in) {
  data_s_free_fn_type ff =
      g_hash_table_lookup(data_s_free_fns, GINT_TO_POINTER(in.type));
  if (ff)
    ff(in);
  return none_data;
}

GHashTable *data_s_print_fns;
void check_data_s_print_fn_type(data_s_print_fn_type pf) {}
void data_s_print(FILE *stream, data_s in) {
  data_s_print_fn_type pf =
      g_hash_table_lookup(data_s_print_fns, GINT_TO_POINTER(in.type));
  if (pf)
    pf(stream, in);
}

#include "pair.h"
#include "empty.h"
#include "number_z.h"
#include "number_q.h"
#include "number_r.h"
#include "symbol.h"
#include "string.h"
#include "boolean.h"
#include "primitive_procedure.h"
#include "undef.h"
#include "error.h"
#include "quote.h"
#include "assignment.h"
#include "definition.h"
#include "if.h"
#include "lambda.h"
#include "procedure.h"
#include "begin.h"
#include "cond.h"
#include "quasiquote.h"
void data_s_fns_init() {
  data_s_new_fns = g_hash_table_new(g_direct_hash, g_direct_equal);
  data_s_copy_fns = g_hash_table_new(g_direct_hash, g_direct_equal);
  data_s_free_fns = g_hash_table_new(g_direct_hash, g_direct_equal);
  data_s_print_fns = g_hash_table_new(g_direct_hash, g_direct_equal);

  /* data_s_free_hash_add(PAIR, pair_free); */
  data_s_print_hash_add(PAIR, pair_print);

  data_s_print_hash_add(EMPTY, empty_print);

  data_s_new_hash_add(Z, number_z_new);
  data_s_copy_hash_add(Z, number_z_copy);
  data_s_free_hash_add(Z, number_z_free);
  data_s_print_hash_add(Z, number_z_print);

  data_s_new_hash_add(Q, number_q_new);
  data_s_copy_hash_add(Q, number_q_copy);
  data_s_free_hash_add(Q, number_q_free);
  data_s_print_hash_add(Q, number_q_print);

  data_s_new_hash_add(R, number_r_new);
  data_s_copy_hash_add(R, number_r_copy);
  data_s_free_hash_add(R, number_r_free);
  data_s_print_hash_add(R, number_r_print);

  obarray = g_hash_table_new(g_str_hash, g_str_equal);
  data_s_new_hash_add(SYMBOL, symbol_new);
  data_s_print_hash_add(SYMBOL, symbol_print);

  data_s_new_hash_add(STRING, string_new);
  data_s_copy_hash_add(STRING, string_copy);
  data_s_free_hash_add(STRING, string_free);
  data_s_print_hash_add(STRING, string_print);

  data_s_print_hash_add(BOOLEAN, boolean_print);

  data_s_new_hash_add(PRIMITIVE_PROCEDURE, primitive_procedure_new);
  data_s_print_hash_add(PRIMITIVE_PROCEDURE, primitive_procedure_print);

  data_s_print_hash_add(PROCEDURE, procedure_print);

  data_s_print_hash_add(UNDEF, undef_print);

  data_s_print_hash_add(ERROR, error_print);

  /* syntax */
  data_s_print_hash_add(QUOTE, quote_print);

  data_s_print_hash_add(ASSIGNMENT, assignment_print);

  data_s_print_hash_add(DEFINITION, definition_print);

  if_sym = data_s_new(SYMBOL, "if");
  data_s_print_hash_add(IF, if_print);

  lambda_sym = data_s_new(SYMBOL, "lambda");
  data_s_print_hash_add(LAMBDA, lambda_print);

  data_s_print_hash_add(BEGIN, begin_print);

  data_s_print_hash_add(COND, cond_print);

  data_s_print_hash_add(QUASIQUOTE, quasiquote_print);
}
#include "definition.h"

const data_s definition_data = {.type = DEFINITION};
void definition_print(FILE *stream, data_s in) {
  fprintf(stream, "#<syntax define>");
}

#include "evaluator.h"
#include "stack.h"
#include "list_operations.h"
#include "lambda.h"
static void ev_definition1();
static void f() {}
void ev_definition() {
  unev = data_s_free(unev);
  data_type type = cadr(expr).type;
  unev = type == SYMBOL ? cadr(expr) : caadr(expr);
  save(unev);
  expr = type == SYMBOL ? caddr(expr) : make_lambda(cdadr(expr), cddr(expr));
  save(env);
  /* save(cont); */
  /* cont.data.fn = ev_definition1; 変更 */
  /* cont.data.fn = f; */
  eval_dispatch();
  ev_definition1();
}
#include "environment.h"
#include "undef.h"
static void ev_definition1() {
  /* cont = restore(); */
  env = restore();
  data_s_free(unev);
  unev = restore();
  define_variable(unev, val, env);
  /* cont.data.fn(); */
}
#include "empty.h"

const data_s empty_data = {.type=EMPTY};

void empty_print(FILE *stream, data_s in) {
  fprintf(stream, "()");
}

#include "boolean.h"
data_s is_null(data_s in) {
  return in.type == EMPTY ? true_data : false_data;
}
#include "environment.h"
#include "list_operations.h"

#include "symbol.h"
#include "error.h"
data_s lookup_variable_value(data_s var, data_s env) {
  while (env.type != EMPTY) {
    data_s frame = car(env);
    data_s vars = car(frame);
    data_s vals = cdr(frame);
    while (vars.type != EMPTY) {
      if (symbol_eq(var, car(vars)))
        return car(vals);
      vars = cdr(vars);
      vals = cdr(vals);
    }
    env = cdr(env);
  }
  fprintf(stderr, "Unbound variable: ");
  data_s_print(stderr, var);
  return error_data;
}

data_s set_variable_value(data_s var, data_s val, data_s env) {
  while (env.type != EMPTY) {
    data_s frame = car(env);
    data_s vars = car(frame);
    data_s vals = cdr(frame);
    while (vars.type != EMPTY) {
      if (symbol_eq(var, car(vars)))
        return set_car(vals, val);
      vars = cdr(vars);
      vals = cdr(vals);
    }
    env = cdr(env);
  }
  fprintf(stderr, "Unbound variable -- SET!: ");
  data_s_print(stderr, var);
  return error_data;
}

static data_s add_binding_to_frame(data_s var, data_s val, data_s frame) {
  set_car(frame, cons(var, car(frame)));
  return set_cdr(frame, cons(val, cdr(frame)));
}
data_s define_variable(data_s var, data_s val, data_s env) {
  data_s frame = car(env);
  data_s vars = car(frame);
  data_s vals = cdr(frame);
  while (vars.type != EMPTY) {
    if (symbol_eq(var, car(vars)))
      return set_car(vals, val);
    vars = cdr(vars);
    vals = cdr(vals);
  }
  return add_binding_to_frame(var, val, frame);
}

static int length(data_s in) {
  int len = 0;
  while (in.type != EMPTY) {
    len++;
    in = cdr(in);
  }
  return len;
}

data_s extend_environment(data_s vars, data_s vals, data_s base_env) {
  int vars_len = length(vars);
  int vals_len = length(vals);
  if (vars_len == vals_len)
    return cons(cons(vars, vals), base_env);
  else if (vars_len < vals_len) {
    fprintf(stderr, "Too many arguments supplied ");
    data_s_print(stderr, vars);
    fprintf(stderr, " ");
    data_s_print(stderr, vals);
    return error_data;
  } else {
    fprintf(stderr, "Too few arguments supplied ");
    data_s_print(stderr, vars);
    fprintf(stderr, " ");
    data_s_print(stderr, vals);
    return error_data;
  }
}

data_s global_environment;
#include "empty.h"
#include "quote.h"
#include "boolean.h"
#include "assignment.h"
#include "definition.h"
#include "if.h"
#include "lambda.h"
#include "begin.h"
#include "cond.h"
#include "quasiquote.h"
#include "primitive_procedure.h"
data_s setup_environment() {
  data_s frame = cons(empty_data, empty_data);
  data_s initial_env = cons(frame, empty_data);

  char *syntax_symbols[] = {"quote",  "set!",  "define", "if",
                            "lambda", "begin", "cond",  "quasiquote"};
  data_s ds[] = {quote_data, assignment_data, definition_data,
                 if_data,    lambda_data,     begin_data,
                 cond_data,  quasiquote_data};
  for (int i = 0; i < 8; i++)
    define_variable(data_s_new(SYMBOL, syntax_symbols[i]), ds[i], initial_env);

  char *boolean_symbols[] = {"#t", "#f"};
  data_s boolean_data[] = {true_data, false_data};
  for (int i = 0; i < 2; i++)
    define_variable(data_s_new(SYMBOL, boolean_symbols[i]), boolean_data[i],
                    initial_env);

  prim_proc_init();
  char *prim_proc_names[] = {
      "car",    "cdr",    "set-car!", "set-cdr", "cons",   "list",   "append",
      "caar",   "cadr",   "cdar",     "cddr",    "caaar",  "caadr",  "cadar",
      "caddr",  "cdaar",  "cdadr",    "cddar",   "cdddr",  "caaaar", "caaadr",
      "caadar", "caaddr", "cadaar",   "cadadr",  "caddar", "cadddr", "cdaaar",
      "cdaadr", "cdadar", "cdaddr",   "cddaar",  "cddadr", "cdddar", "cddddr",
      "+",      "-",      "*",        "/",       "=",      "<"};
  for (int i = 0; i < 41; i++)
    define_variable(data_s_new(SYMBOL, prim_proc_names[i]),
                    primitive_procedure_new(prim_proc_names[i]), initial_env);

  return initial_env;
}
#include "error.h"

const data_s error_data = {.type=ERROR};

void error_print(FILE *stream, data_s in) {
  fprintf(stream, "ERROR");
}

#include "evaluator.h"
#include "repl.h"
void ev_error() {
  printf("\n");
  data_s_print(stdout, val);
  printf("\n");
  read_eval_print_loop();
}
#include "evaluator.h"

data_s expr = {.type = NONE};
data_s env = {.type = NONE};
data_s val = {.type = NONE};
data_s cont = {.type = NONE};
data_s proc = {.type = NONE};
data_s argl = {.type = NONE};
data_s unev = {.type = NONE};

GHashTable *eval_fns;
void check_eval_fn_type(eval_fn_type ef) {}

#include "self_evaluating.h"
#include "variable.h"
#include "list_operations.h"
#include "application.h"
#include "environment.h"
int eval_flag;
void eval_dispatch() {
  do {
    eval_flag = 0;
    if (is_self_evaluating(expr)) {
      ev_self_eval();
    } else if (is_variable(expr))
      ev_variable();
    else {
      data_s t1 = car(expr);
      if (t1.type == PAIR) {
        ev_application();
      } else {
        data_s t2 = lookup_variable_value(t1, env);
        eval_fn_type ef =
            g_hash_table_lookup(eval_fns, GINT_TO_POINTER(t2.type));
        data_s_free(t1);
        data_s_free(t2);
        if (!ef) {
          ev_application();
        } else {
          ef();
        }
      }
    }
  } while (eval_flag);
}

#include "quote.h"
#include "assignment.h"
#include "definition.h"
#include "if.h"
#include "lambda.h"
#include "begin.h"
#include "cond.h"
void eval_fns_init() {
  eval_fns = g_hash_table_new(g_direct_hash, g_direct_equal);

  data_type types[] = {QUOTE, ASSIGNMENT, DEFINITION, IF, COND, LAMBDA, BEGIN};
  eval_fn_type fns[] = {ev_quoted, ev_assignment, ev_definition, ev_if,
                        ev_cond,   ev_lambda,     ev_begin};
  for (int i = 0; i < 7; i++)
    eval_hash_add(types[i], fns[i]);
}
#include "expressions.h"
#include "list_operations.h"

extern data_s true_data;
extern data_s false_data;
extern data_s empty_data;
extern data_s error_data;
extern data_s undef;

bool is_self_evaluating(data_s in) {
  switch (in.type) {
  case Z:
  case Q:
  case R:
  case CHAR:
  case STRING:
  case BOOL:
    return true;
  default:
    return false;
  }
}

bool is_variable(data_s in) { return in.type == SYMBOL; }

bool is_tagged_list(data_s in1, char *s) {
  if (in1.type == PAIR) {
    data_s t = car(in1);
    if (t.type == SYMBOL && strcmp(t.data.symbol, s) == 0)
      return true;
  }
  return false;
}

bool is_quoted(data_s in) { return is_tagged_list(in, "quote"); }

data_s text_of_quotation(data_s in) { return car(cdr(in)); }

bool is_assignment(data_s in) { return is_tagged_list(in, "set!"); }

data_s assignment_variable(data_s in) { return car(cdr(in)); }

data_s assignment_value(data_s in) { return car(cdr(cdr(in))); }

bool is_definition(data_s in) { return is_tagged_list(in, "define"); }

data_s definition_variable(data_s in) {
  data_s t = car(cdr(in));
  return t.type == SYMBOL ? car(cdr(in)) : car(car(cdr(in)));
}

data_s definition_value(data_s in) {
  data_s t = car(cdr(in));
  return t.type == SYMBOL ? car(cdr(cdr(in)))
                          : make_lambda(cdr(car(cdr(in))), cdr(cdr(in)));
}

bool is_lambda(data_s in) { return is_tagged_list(in, "lambda"); }

data_s lambda_parameters(data_s in) { return car(cdr(in)); }

data_s lambda_body(data_s in) { return cdr(cdr(in)); }

data_s lambda;
data_s make_lambda(data_s parameters, data_s body) {
  return cons(lambda, cons(parameters, body));
}

bool is_if(data_s in) { return is_tagged_list(in, "if"); }

data_s if_predicate(data_s in) { return car(cdr(in)); }

data_s if_consequent(data_s in) { return car(cdr(cdr(in))); }

data_s if_alternative(data_s in) {
  data_s t = cdr(cdr(cdr(in)));
  return t.type != EMPTY ? car(cdr(cdr(cdr(in)))) : false_data;
}

data_s make_if(data_s predicate, data_s consequent, data_s alternative) {
  data_s if_sym = symbol_new("if");
  return cons(if_sym,
              cons(predicate, cons(consequent, cons(alternative,
                                                    (data_s){.type = EMPTY}))));
}

bool is_begin(data_s in) { return is_tagged_list(in, "begin"); }

data_s begin_actions(data_s in) { return cdr(in); }

bool is_last_expr(data_s in) {
  data_s t = cdr(in);
  return t.type == EMPTY;
}
data_s first_expr(data_s in) { return car(in); }

data_s rest_exprs(data_s in) { return cdr(in); }

data_s sequence2expr(data_s in) {
  if (in.type == EMPTY)
    return in;
  if (is_last_expr(in))
    return first_expr(in);
  return make_begin(in);
}

data_s make_begin(data_s in) {
  data_s begin = symbol_new("begin");
  return cons(begin, in);
}

bool is_application(data_s in) { return in.type == PAIR; }

data_s operator(data_s in) { return car(in); }

data_s operands(data_s in) { return cdr(in); }

bool no_operands(data_s in) { return in.type == EMPTY; }

data_s first_operand(data_s in) { return car(in); }

data_s rest_operands(data_s in) { return cdr(in); }

bool is_cond(data_s in) { return is_tagged_list(in, "cond"); }

data_s cond_clauses(data_s in) { return cdr(in); }

bool is_cond_else_clause(data_s in) {
  return is_tagged_list(cond_predicate(in), "else");
}

data_s cond_predicate(data_s in) { return car(in); }

data_s cond_actions(data_s in) { return cdr(in); }

data_s expand_clauses(data_s in) {
  if (in.type == EMPTY)
    return false_data;
  data_s first = car(in), rest = cdr(in);
  if (is_cond_else_clause(first)) {
    if (rest.type == EMPTY)
      return sequence2expr(cond_actions(first));
    return error("ELSE clause isn't last -- COND->IF", 1, in);
  }
  return make_if(cond_predicate(first), sequence2expr(cond_actions(first)),
                 expand_clauses(rest));
}
#include "garbage_collector.h"
#include "list_operations.h"
#include "evaluator.h"
#include "stack.h"
#include <string.h>
#include <stdlib.h> // exit

static void mark(data_s in);
void begin_garbage_collection() {
  data_s t = {.type = PAIR, .data.index = free_index};
  data_s root[] = {expr, env, val, cont, proc, argl, unev, stack, t};
  marker_count = 0;
  memset(markers, 0, sizeof(char) * memory_size);
  for (int i = 0; i < 9; i++)
    mark(root[i]);
  if (marker_count == memory_size) {
    fprintf(stderr, "メモリーが不足しています。\n");
    exit(0);
  }
  for (int i = 0; i < memory_size; i++)
    if (*(markers + i) == 0) {
      *(cars + i) = data_s_free(*(cars + i));
      *(cdrs + i) = data_s_free(*(cdrs + i));
    }
}

static void mark(data_s in) {
  if ((in.type == PAIR || in.type == PROCEDURE) &&
      *(markers + in.data.index) == 0) {
    marker_count++;
    *(markers + in.data.index) = 1;
    data_s h = car(in);
    mark(h);
    data_s t = cdr(in);
    mark(t);
  }
}
#include "if.h"

const data_s if_data = {.type=IF};

void if_print(FILE *stream, data_s in) {
  fprintf(stream, "#<syntax if>");
}


#include "evaluator.h"
#include "stack.h"
#include "list_operations.h"
static void ev_if_decide();

void ev_if() {
  save(expr);
  save(env);
  expr = cadr(expr);  
  eval_dispatch();
  ev_if_decide();               /* 追加 */
}

#include "boolean.h"
static void ev_if_consequent();
static void ev_if_alternative();
static void ev_if_decide() {
  env = restore();
  expr = data_s_free(expr);
  expr = restore();
  if (is_true(val))
    ev_if_consequent();
  else
    ev_if_alternative();
}

static data_s if_alternative(data_s in);
static void ev_if_alternative() {  
  expr = if_alternative(expr);
  /* eval_dispatch(); */
  eval_flag = 1;
}
static void ev_if_consequent() {
  expr = caddr(expr);
  /* eval_dispatch(); */
  eval_flag = 1;
}

#include "undef.h"
static data_s if_alternative(data_s in) {
  data_s t = cdddr(in);
  return t.type == EMPTY ? undef : car(t);
}

data_s if_sym;
data_s make_if(data_s in1, data_s in2, data_s in3) {
  return list(4, if_sym , in1, in2, in3);
}
#include "kread.h"
#include <stdlib.h> // exit
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include "list_operations.h"
#include "stopif.h"
#include <errno.h>
static void skip_spaces(FILE *in);
static void skip_line(FILE *in);
static data_s read_pair(FILE *in);
static data_s read_atom(FILE *in);

static data_s read_number(FILE *in);
static data_s read_symbol(FILE *in);
static data_s read_char(FILE *in);
static data_s read_string(FILE *in);

data_s kread(FILE *in) {
  data_s out;
  skip_spaces(in);
  char ch = fgetc(in);
  Stopif(ch == EOF && ferror(in), exit(1), "%s", strerror(errno));
  if (ch == EOF)
    exit(0);
  if (ch == ';') {
    skip_line(in);
    out = kread(in);
  } else if (ch == '(') {
    out = read_pair(in);
  } else {
    Stopif(ungetc(ch, in) == EOF && ferror(in), exit(1), "%s", strerror(errno));
    out = read_atom(in);
  }
  return out;
}

static void skip_spaces(FILE *in) {
  char ch;
  while (isspace(ch = fgetc(in)))
    ;
  Stopif(ungetc(ch, in) == EOF && ferror(in), exit(1), "%s", strerror(errno));
}
static void skip_line(FILE *in) {
  char ch;
  while ((ch =fgetc(in)) != '\n')
      Stopif(ch == EOF && ferror(in), exit(1), "%s", strerror(errno));;
}

#include "empty.h"
static data_s read_pair(FILE *in) {
  skip_spaces(in);
  char ch = fgetc(in);
  Stopif(ch == EOF && ferror(in), exit(1), "%s", strerror(errno));
  if (ch == ')')
    return empty_data;
  Stopif(ungetc(ch, in) == EOF && ferror(in), exit(1), "%s", strerror(errno));
  data_s a = kread(in);
  skip_spaces(in);
  ch = fgetc(in);
  Stopif(ch == EOF && ferror(in), exit(1), "%s", strerror(errno));
  if (ch == ')')
    return cons(a, empty_data);
  Stopif(ungetc(ch, in) == EOF && ferror(in), exit(1), "%s", strerror(errno));
  Stopif(ungetc('(', in) == EOF && ferror(in), exit(1), "%s", strerror(errno));
  return cons(a, kread(in));
}

static data_s read_atom(FILE *in) {
  data_s out;
  char ch = fgetc(in);
  Stopif(ch == EOF && ferror(in), exit(1), "%s", strerror(errno));
  char ch1 = '\0';
  if (ch == '\'') {
    out = kread(in);
    out = cons(out, empty_data);
    out = cons(data_s_new(SYMBOL, "quote"), out);
  } else if (ch == '"')
    out = read_string(in);
  else if (ch == '#') {
    ch = fgetc(in);
    Stopif(ch == EOF && ferror(in), exit(1), "%s", strerror(errno));    
    if (ch == 't')
      out = data_s_new(SYMBOL, "#t");
    else if (ch == 'f')
      out = data_s_new(SYMBOL, "#f");
    else if (ch == '\\')
      out = read_char(in);
  } else if (isdigit(ch)) {
    Stopif(ungetc(ch, in) == EOF && ferror(in), exit(1), "%s", strerror(errno));
    out = read_number(in);
  } else if ((ch == '+' || ch == '-') && isdigit(ch1 = fgetc(in))) {
    Stopif(ungetc(ch1, in) == EOF && ferror(in), exit(1), "%s",
           strerror(errno));
    Stopif(ungetc(ch, in) == EOF && ferror(in), exit(1), "%s",
           strerror(errno));
    out = read_number(in);
  } else {
    if (ch1 != '\0')
      Stopif(ungetc(ch1, in) == EOF && ferror(in), exit(1), "%s",
             strerror(errno));
    Stopif(ungetc(ch, in) == EOF && ferror(in), exit(1), "%s", strerror(errno));
    out = read_symbol(in);
  }
  return out;
}

static data_s read_number(FILE *in) {
  static int number_size = 1000000;
  data_s out;
  char s[number_size];
  int i = 0;
  char ch = fgetc(in);
  Stopif(ferror(in), exit(1), "%s", strerror(errno));
  s[i] = ch;
  i++;
  while (isdigit(ch = fgetc(in))) {
    s[i] = ch;
    i++;
  }
  if (ch == '.') {
    s[i] = ch;
    i++;
    while (isdigit(ch = fgetc(in))) {
      s[i] = ch;
      i++;
    }
    s[i] = '\0';
    if (ch == '(' || ch == ')')
      Stopif(ungetc(ch, in) == EOF && ferror(in), exit(1), "%s",
             strerror(errno));
    out = data_s_new(R, s);
  } else if (ch == '/') {
    s[i] = ch;
    i++;
    while (isdigit(ch = fgetc(in))) {
      s[i] = ch;
      i++;
    }
    s[i] = '\0';
    if (ch == '(' || ch == ')')
      Stopif(ungetc(ch, in) == EOF && ferror(in), exit(1), "%s",
             strerror(errno));
    out = data_s_new(Q, s);
  } else {
    s[i] = '\0';
    if (ch == '(' || ch == ')')
      Stopif(ungetc(ch, in) == EOF && ferror(in), exit(1), "%s",
             strerror(errno));
    out = data_s_new(Z, s);
  }
  return out;
}

#define symbol_size 100
static data_s read_symbol(FILE *in) {
  /* static const int symbol_size = 100; */
  static char symbol[symbol_size];
  int i;
  char ch = fgetc(in);
  Stopif(ch == EOF && ferror(in), exit(1), "%s", strerror(errno));
  for (i = 0; !isspace(ch) && ch != '(' && ch != ')'; i++) {
    symbol[i] = ch;
    ch = fgetc(in);
    Stopif(ch == EOF && ferror(in), exit(1), "%s", strerror(errno));
  }
  symbol[i] = '\0';
  if (ch == '(' || ch == ')')
    Stopif(ungetc(ch, in) == EOF && ferror(in), exit(1), "%s", strerror(errno));
  data_s out = data_s_new(SYMBOL, symbol);
  return out;
}

static data_s read_char(FILE *in) {
  data_s out = {.type = CHAR, .data.ch = fgetc(in)};
  return out;
}

data_s read_string(FILE *in) {
  static int str_size = 1000000;
  data_s out;
  char str[str_size];
  int i = 0;
  while (1) {
    char ch = fgetc(in);
    Stopif(ch == EOF && ferror(in), exit(1), "%s", strerror(errno));
    if (ch == '\\') {
      str[i] = ch;
      i++;
      ch = fgetc(in);
      Stopif(ch == EOF && ferror(in), exit(1), "%s", strerror(errno));
      str[i] = ch;
      i++;
    } else if (ch == '\"') {
      str[i] = '\0';
      break;
    } else {
      str[i] = ch;
      i++;
    }
  }
  out = data_s_new(STRING, str);
  return out;
}
#include "lambda.h"

const data_s lambda_data = {.type=LAMBDA};

void lambda_print(FILE *stream, data_s in) {
  fprintf(stream, "#<syntax lambda>");
}

#include "evaluator.h"
#include "list_operations.h"
#include "procedure.h"
void ev_lambda() {
  unev = data_s_free(unev);
  unev = cadr(expr);
  expr = cddr(expr);
  val = data_s_free(val);
  val = make_procedure(unev, expr, env);
}

data_s lambda_sym;
data_s make_lambda(data_s in1, data_s in2) {
  return cons(lambda_sym, cons(in1, in2));
}
#include "list_operations.h"

/* const int memory_size = 32768; /\* gcc *\/ */
const int memory_size = 15932; /* clang */

data_s *cars;
data_s *cdrs;
char *markers;
data_s car(data_s in) { return data_s_copy(*(cars + in.data.index)); }
data_s cdr(data_s in) { return data_s_copy(*(cdrs + in.data.index)); }
#include "undef.h"
data_s set_car(data_s in1, data_s in2) {
  data_s_free(*(cars + in1.data.index));
  *(cars + in1.data.index) = data_s_copy(in2);
  return undef;
}

data_s set_cdr(data_s in1, data_s in2) {
  data_s_free(*(cdrs + in1.data.index));
  *(cdrs + in1.data.index) = data_s_copy(in2);
  return undef;
}

#include "garbage_collector.h"
int marker_count = 0;
int free_index = 0;
data_s cons(data_s in1, data_s in2) {
  *(markers + free_index) += 1;
  marker_count++;
  data_s out = {.type = PAIR, .data.index = free_index};
  *(cars + free_index) = data_s_copy(in1);
  *(cdrs + free_index) = data_s_copy(in2);

  if (marker_count == memory_size) {
    /* printf("garbage_collector start\n"); */
    /* printf("%d\n", marker_count); */
    begin_garbage_collection();
    /* printf("%d\n", marker_count); */
    /* printf("garbage_collector stop\n"); */
  }

  free_index++;
  while (1) {
    if (free_index == memory_size)
      free_index = 0;
    if (*(markers + free_index) == 0)
      break;
    free_index++;
  }
  return out;
}

#include "undef.h"
data_s set(data_s *in1, data_s in2) {
  data_s_free(*in1);
  *in1 = data_s_copy(in2);
  return undef;
}

#include "empty.h"
data_s list(int args, ...) {
  data_s data_array[args];
  data_s out = empty_data;
  va_list ap;
  va_start(ap, args);
  for (int i = 0; i < args; i++)
    *(data_array + i) = va_arg(ap, data_s);
  va_end(ap);
  for (int i = args; i > 0; i--) {
    out = cons(*(data_array + i - 1), out);
  }
  return out;
}

data_s append(data_s in1, data_s in2) {
  if (in1.type == EMPTY)
    return in2;
  return cons(car(in1), append(cdr(in1), in2));
}

data_s caar(data_s in) { return car(car(in)); }
data_s cadr(data_s in) { return car(cdr(in)); }
data_s cdar(data_s in) { return cdr(car(in)); }
data_s cddr(data_s in) { return cdr(cdr(in)); }
data_s caaar(data_s in) { return car(car(car(in))); }
data_s caadr(data_s in) { return car(car(cdr(in))); }
data_s cadar(data_s in) { return car(cdr(car(in))); }
data_s caddr(data_s in) { return car(cdr(cdr(in))); }
data_s cdaar(data_s in) { return cdr(car(car(in))); }
data_s cdadr(data_s in) { return cdr(car(cdr(in))); }
data_s cddar(data_s in) { return cdr(cdr(car(in))); }
data_s cdddr(data_s in) { return cdr(cdr(cdr(in))); }
data_s caaaar(data_s in) { return car(car(car(car(in)))); }
data_s caaadr(data_s in) { return car(car(car(cdr(in)))); }
data_s caadar(data_s in) { return car(car(cdr(car(in)))); }
data_s caaddr(data_s in) { return car(car(cdr(cdr(in)))); }
data_s cadaar(data_s in) { return car(cdr(car(car(in)))); }
data_s cadadr(data_s in) { return car(cdr(car(cdr(in)))); }
data_s caddar(data_s in) { return car(cdr(cdr(car(in)))); }
data_s cadddr(data_s in) { return car(cdr(cdr(cdr(in)))); }
data_s cdaaar(data_s in) { return cdr(car(car(car(in)))); }
data_s cdaadr(data_s in) { return cdr(car(car(cdr(in)))); }
data_s cdadar(data_s in) { return cdr(car(cdr(car(in)))); }
data_s cdaddr(data_s in) { return cdr(car(cdr(cdr(in)))); }
data_s cddaar(data_s in) { return cdr(cdr(car(car(in)))); }
data_s cddadr(data_s in) { return cdr(cdr(car(cdr(in)))); }
data_s cdddar(data_s in) { return cdr(cdr(cdr(car(in)))); }
data_s cddddr(data_s in) { return cdr(cdr(cdr(cdr(in)))); }
#include "data.h"
#include "list_operations.h"
#include "stack.h"
#include <string.h>
#include "environment.h"
#include "evaluator.h"
#include "repl.h"

int main(int args, char *argv[]) {
  data_s memory[2][memory_size];
  cars = memory[0];
  cdrs = memory[1];
  char memory_markers[memory_size];
  memset(memory_markers, 0, sizeof(memory_markers));
  markers = memory_markers;
  data_s_fns_init();
  global_environment = setup_environment();
  eval_fns_init();
  read_eval_print_loop();
}
#include "none.h"

const data_s none_data = {.type=NONE};
#include "number.h"
#include <gmp.h>

#include "boolean.h"
data_s is_number(data_s in) {
  return in.type == Z || in.type == Q || in.type == R ? true_data : false_data;
}
#include "number_q.h"
#include <gmp.h>

data_s number_q_new(char *in) {
  data_s out = {.type=Q};
  mpq_init(out.data.q);
  mpq_set_str(out.data.q, in, 10);
  return out;
}

data_s number_q_copy(data_s in) {
  data_s out = {.type=Q};
  mpq_set(out.data.q, in.data.q);
  return out;
}

void number_q_free(data_s in) {
  mpq_clear(in.data.q);
}

#include <stdio.h>
void number_q_print(FILE *stream, data_s in) {
  mpq_canonicalize(in.data.q);
  mpq_out_str(stream, 10, in.data.q);
}

bool number_q_eq(data_s in1, data_s in2) {
  return mpq_equal(in1.data.q, in2.data.q);
}
#include "number_r.h"
#include <gmp.h>

data_s number_r_new(char *in) {
  data_s out = {.type=R};
  mpf_init_set_str(out.data.r, in, 10);
  return out;
}

data_s number_r_copy(data_s in) {
  data_s out = {.type=R};
  mpf_init_set(out.data.r, in.data.r);
  return out;
}

void number_r_free(data_s in) {
  mpf_clear(in.data.r);
}

void number_r_print(FILE *stream, data_s in) {
  mpf_out_str(stream, 10, 0, in.data.r);
}

bool number_r_eq(data_s in1, data_s in2) {
  return mpf_cmp(in1.data.r, in2.data.r) == 0;
}
#include "number_z.h"
#include <gmp.h>
#include "stopif.h"

data_s number_z_new(char *in) {
  data_s out = {.type=Z};
  Stopif(mpz_init_set_str(out.data.z, in, 10) == -1,
         exit(1),
         "整数割り当て失敗");
  return out;
}

data_s number_z_copy(data_s in) {
  data_s out = {.type=Z};
  mpz_init_set(out.data.z, in.data.z);
  return out;
}

void number_z_free(data_s in) {
  mpz_clear(in.data.z);
}

void number_z_print(FILE *stream, data_s in) {
  mpz_out_str(stream, 10, in.data.z);
}

bool number_z_eq(data_s in1, data_s in2) {
  return mpz_cmp(in1.data.z, in2.data.z) == 0;
}
#include "pair.h"
#include "list_operations.h"

/* void pair_free(data_s in) { */
/*   int i = in.data.index; */
/*   data_s_free(*(cars + i)); */
/*   data_s_free(*(cdrs + i)); */
/* } */

static void pair_print_inner(FILE *stream, data_s in, int flag) {
  if (flag)
    fprintf(stream, "(");
  int i = in.data.index;

  data_s h = *(cars + i);
  if (h.type == PAIR)
    pair_print_inner(stream, h, 1);
  else
    data_s_print(stream, h);

  data_s t = *(cdrs + i);
  if (t.type == EMPTY)
    fprintf(stream, ")");
  else if (t.type == PAIR) {
    fprintf(stream, " ");
    pair_print_inner(stream, t, 0);
  } else {
    fprintf(stream, " . ");
    data_s_print(stream, t);
    fprintf(stream, ")");
  }
}
void pair_print(FILE *stream, data_s in) { pair_print_inner(stream, in, 1); }

bool pair_eq(data_s in1, data_s in2) {
  return in1.data.index == in2.data.index;
}
#include "prim_list_procedures.h"
#include "list_operations.h"

data_s prim_car(data_s in) { return car(car(in)); }
data_s prim_cdr(data_s in) { return cdr(car(in)); }
data_s prim_set_car(data_s in) { return set_car(car(in), cadr(in)); }
data_s prim_set_cdr(data_s in) { return set_cdr(car(in), cadr(in)); }

data_s prim_cons(data_s in) { return cons(car(in), cadr(in)); }

static int length(data_s in) {
  int len = 0;
  while (in.type != EMPTY) {
    len++;
    in = cdr(in);
  }
  return len;
}
#include "empty.h"
data_s prim_list(data_s in) {
  int len = length(in);
  data_s data_array[len];
  for (int i = 0; i < len; i++) {
    *(data_array + i) = car(in);
    in = cdr(in);
  }
  data_s out = empty_data;
  for (int i = len; i > 0; i--)
    out = cons(*(data_array + i - 1), out);
  return out;
}

data_s prim_append(data_s in) { return append(car(in), cadr(in)); }

data_s prim_caar(data_s in) { return car(car(in)); }
data_s prim_cadr(data_s in) { return car(cdr(in)); }
data_s prim_cdar(data_s in) { return cdr(car(in)); }
data_s prim_cddr(data_s in) { return cdr(cdr(in)); }
data_s prim_caaar(data_s in) { return car(car(car(in))); }
data_s prim_caadr(data_s in) { return car(car(cdr(in))); }
data_s prim_cadar(data_s in) { return car(cdr(car(in))); }
data_s prim_caddr(data_s in) { return car(cdr(cdr(in))); }
data_s prim_cdaar(data_s in) { return cdr(car(car(in))); }
data_s prim_cdadr(data_s in) { return cdr(car(cdr(in))); }
data_s prim_cddar(data_s in) { return cdr(cdr(car(in))); }
data_s prim_cdddr(data_s in) { return cdr(cdr(cdr(in))); }
data_s prim_caaaar(data_s in) { return car(car(car(car(in)))); }
data_s prim_caaadr(data_s in) { return car(car(car(cdr(in)))); }
data_s prim_caadar(data_s in) { return car(car(cdr(car(in)))); }
data_s prim_caaddr(data_s in) { return car(car(cdr(cdr(in)))); }
data_s prim_cadaar(data_s in) { return car(cdr(car(car(in)))); }
data_s prim_cadadr(data_s in) { return car(cdr(car(cdr(in)))); }
data_s prim_caddar(data_s in) { return car(cdr(cdr(car(in)))); }
data_s prim_cadddr(data_s in) { return car(cdr(cdr(cdr(in)))); }
data_s prim_cdaaar(data_s in) { return cdr(car(car(car(in)))); }
data_s prim_cdaadr(data_s in) { return cdr(car(car(cdr(in)))); }
data_s prim_cdadar(data_s in) { return cdr(car(cdr(car(in)))); }
data_s prim_cdaddr(data_s in) { return cdr(car(cdr(cdr(in)))); }
data_s prim_cddaar(data_s in) { return cdr(cdr(car(car(in)))); }
data_s prim_cddadr(data_s in) { return cdr(cdr(car(cdr(in)))); }
data_s prim_cdddar(data_s in) { return cdr(cdr(cdr(car(in)))); }
data_s prim_cddddr(data_s in) { return cdr(cdr(cdr(cdr(in)))); }
#include "prim_number_procedures.h"
#include "list_operations.h"
#include <gmp.h>

static data_s number_add(data_s in1, data_s in2);
static data_s number_sub(data_s in1, data_s in2);
static data_s number_mul(data_s in1, data_s in2);
static data_s number_div(data_s in1, data_s in2);
static data_s number_eq(data_s in1, data_s in2);
static data_s number_less_than(data_s in1, data_s in2);

data_s prim_number_add(data_s in) { return number_add(car(in), car(cdr(in))); }
data_s prim_number_sub(data_s in) { return number_sub(car(in), car(cdr(in))); }
data_s prim_number_mul(data_s in) { return number_mul(car(in), car(cdr(in))); }
data_s prim_number_div(data_s in) { return number_div(car(in), car(cdr(in))); }
data_s prim_number_eq(data_s in) { return number_eq(car(in), car(cdr(in))); }
data_s prim_number_less_than(data_s in) {
  return number_less_than(car(in), car(cdr(in)));
}

#include "error.h"
static data_s number_add(data_s in1, data_s in2) {
  data_s out;
  if (in1.type == Z) {
    if (in2.type == Z) {
      out.type = Z;
      mpz_init(out.data.z);
      mpz_add(out.data.z, in1.data.z, in2.data.z);
    } else if (in2.type == Q) {
      out.type = Q;
      mpq_init(out.data.q);
      mpq_t x;
      mpq_init(x);
      mpq_set_z(x, in1.data.z);
      mpq_add(out.data.q, x, in2.data.q);
      mpq_clear(x);
    } else if (in2.type == R) {
      out.type = R;
      mpf_init(out.data.r);
      mpf_t x;
      mpf_init(x);
      mpf_set_z(x, in1.data.z);
      mpf_add(out.data.r, x, in2.data.r);
      mpf_clear(x);
    } else {
      out = error_data;
    }
  } else if (in1.type == Q) {
    if (in2.type == Z)
      out = number_add(in2, in1);
    else if (in2.type == Q) {
      out.type = Q;
      mpq_init(out.data.q);
      mpq_add(out.data.q, in1.data.q, in2.data.q);
    } else if (in2.type == R) {
      out.type = R;
      mpf_init(out.data.r);
      mpf_t x;
      mpf_init(x);
      mpf_set_q(x, in1.data.q);
      mpf_add(out.data.r, x, in2.data.r);
      mpf_clear(x);
    } else
      out = error_data;
  } else if (in1.type == R) {
    if (in2.type == Z)
      out = number_add(in2, in1);
    else if (in2.type == Q)
      out = number_add(in2, in1);
    else if (in2.type == R) {
      out.type = R;
      mpf_init(out.data.r);
      mpf_add(out.data.r, in1.data.r, in2.data.r);
    } else
      out = error_data;
  } else
    out = error_data;
  return out;
}

static data_s number_sub(data_s in1, data_s in2) {
  data_s out;
  if (in1.type == Z) {
    if (in2.type == Z) {
      out.type = Z;
      mpz_init(out.data.z);
      mpz_sub(out.data.z, in1.data.z, in2.data.z);
    } else if (in2.type == Q) {
      out.type = Q;
      mpq_init(out.data.q);
      mpq_t x;
      mpq_init(x);
      mpq_set_z(x, in1.data.z);
      mpq_sub(out.data.q, x, in2.data.q);
      mpq_clear(x);
    } else if (in2.type == R) {
      out.type = R;
      mpf_init(out.data.r);
      mpf_t x;
      mpf_init(x);
      mpf_set_z(x, in1.data.z);
      mpf_sub(out.data.r, x, in2.data.r);
      mpf_clear(x);
    } else {
      out = error_data;
    }
  } else if (in1.type == Q) {
    if (in2.type == Z) {
      out.type = Q;
      mpq_init(out.data.q);
      mpq_t x;
      mpq_init(x);
      mpq_set_z(x, in2.data.z);
      mpq_sub(out.data.q, in1.data.q, x);
      mpq_clear(x);
    } else if (in2.type == Q) {
      out.type = Q;
      mpq_init(out.data.q);
      mpq_sub(out.data.q, in1.data.q, in2.data.q);
    } else if (in2.type == R) {
      out.type = R;
      mpf_init(out.data.r);
      mpf_t x;
      mpf_init(x);
      mpf_set_q(x, in1.data.q);
      mpf_sub(out.data.r, x, in2.data.r);
      mpf_clear(x);
    } else {
      out = error_data;
    }
  } else if (in1.type == R) {
    out.type = R;
    mpf_init(out.data.r);
    if (in2.type == Z) {
      mpf_t x;
      mpf_init(x);
      mpf_set_z(x, in2.data.z);
      mpf_sub(out.data.r, in1.data.r, x);
      mpf_clear(x);
    } else if (in2.type == Q) {
      mpf_t x;
      mpf_init(x);
      mpf_set_q(x, in2.data.q);
      mpf_sub(out.data.r, in1.data.r, x);
      mpf_clear(x);
    } else if (in2.type == R) {
      mpf_sub(out.data.r, in1.data.r, in2.data.r);
    } else {
      out = error_data;
    }
  } else {
    out = error_data;
  }
  return out;
}

static data_s number_mul(data_s in1, data_s in2) {
  data_s out;
  if (in1.type == Z) {
    if (in2.type == Z) {
      out.type = Z;
      mpz_init(out.data.z);
      mpz_mul(out.data.z, in1.data.z, in2.data.z);
    } else if (in2.type == Q) {
      out.type = Q;
      mpq_init(out.data.q);
      mpq_t x;
      mpq_init(x);
      mpq_set_z(x, in1.data.z);
      mpq_mul(out.data.q, x, in2.data.q);
      mpq_clear(x);
    } else if (in2.type == R) {
      out.type = R;
      mpf_init(out.data.r);
      mpf_t x;
      mpf_init(x);
      mpf_set_z(x, in1.data.z);
      mpf_mul(out.data.r, x, in2.data.r);
      mpf_clear(x);
    } else {
      out = error_data;
    }
  } else if (in1.type == Q) {
    if (in2.type == Z)
      out = number_mul(in2, in1);
    else if (in2.type == Q) {
      out.type = Q;
      mpq_init(out.data.q);
      mpq_mul(out.data.q, in1.data.q, in2.data.q);
    } else if (in2.type == R) {
      out.type = R;
      mpf_init(out.data.r);
      mpf_t x;
      mpf_init(x);
      mpf_set_q(x, in1.data.q);
      mpf_mul(out.data.r, x, in2.data.r);
      mpf_clear(x);
    } else
      out = error_data;
  } else if (in1.type == R) {
    if (in2.type == Z)
      out = number_mul(in2, in1);
    else if (in2.type == Q)
      out = number_mul(in2, in1);
    else if (in2.type == R) {
      out.type = R;
      mpf_init(out.data.r);
      mpf_mul(out.data.r, in1.data.r, in2.data.r);
    } else
      out = error_data;
  } else
    out = error_data;
  return out;
}

static data_s number_div(data_s in1, data_s in2) {
  data_s out;
  if (in1.type == Z) {
    if (in2.type == Z) {
      out.type = Q;
      mpq_init(out.data.q);
      mpq_t x, y;
      mpq_init(x);
      mpq_init(y);
      mpq_set_z(x, in1.data.z);
      mpq_set_z(y, in2.data.z);
      mpq_div(out.data.q, x, y);
      mpq_clear(x);
      mpq_clear(y);
    } else if (in2.type == Q) {
      out.type = Q;
      mpq_init(out.data.q);
      mpq_t x;
      mpq_init(x);
      mpq_set_z(x, in1.data.z);
      mpq_div(out.data.q, x, in2.data.q);
      mpq_clear(x);
    } else if (in2.type == R) {
      out.type = R;
      mpf_init(out.data.r);
      mpf_t x;
      mpf_init(x);
      mpf_set_z(x, in1.data.z);
      mpf_div(out.data.r, x, in2.data.r);
      mpf_clear(x);
    } else {
      out = error_data;
    }
  } else if (in1.type == Q) {
    if (in2.type == Z) {
      out.type = Q;
      mpq_init(out.data.q);
      mpq_t x;
      mpq_init(x);
      mpq_set_z(x, in2.data.z);
      mpq_div(out.data.q, in1.data.q, x);
      mpq_clear(x);
    } else if (in2.type == Q) {
      out.type = Q;
      mpq_init(out.data.q);
      mpq_div(out.data.q, in1.data.q, in2.data.q);
    } else if (in2.type == R) {
      out.type = R;
      mpf_init(out.data.r);
      mpf_t x;
      mpf_init(x);
      mpf_set_q(x, in1.data.q);
      mpf_div(out.data.r, x, in2.data.r);
      mpf_clear(x);
    } else {
      out = error_data;
    }
  } else if (in1.type == R) {
    out.type = R;
    mpf_init(out.data.r);
    if (in2.type == Z) {
      mpf_t x;
      mpf_init(x);
      mpf_set_z(x, in2.data.z);
      mpf_div(out.data.r, in1.data.r, x);
      mpf_clear(x);
    } else if (in2.type == Q) {
      mpf_t x;
      mpf_init(x);
      mpf_set_q(x, in2.data.q);
      mpf_div(out.data.r, in1.data.r, x);
      mpf_clear(x);
    } else if (in2.type == R) {
      mpf_div(out.data.r, in1.data.r, in2.data.r);
    } else {
      out = error_data;
    }
  } else {
    out = error_data;
  }
  return out;
}

#include "boolean.h"
static data_s number_eq(data_s in1, data_s in2) {
  data_s out;
  if (in1.type == Z) {
    if (in2.type == Z) {
      out = mpz_cmp(in1.data.z, in2.data.z) == 0 ? true_data : false_data;
    } else if (in2.type == Q) {
      mpq_t x;
      mpq_init(x);
      mpq_set_z(x, in1.data.z);
      out = mpq_equal(x, in2.data.q) != 0 ? true_data : false_data;
      mpq_clear(x);
    } else if (in2.type == R) {
      mpf_t x;
      mpf_init(x);
      mpf_set_z(x, in1.data.z);
      out = mpf_cmp(x, in2.data.r) == 0 ? true_data : false_data;
      mpf_clear(x);
    } else {
      out = error_data;
    }
  } else if (in1.type == Q) {
    if (in2.type == Z)
      out = number_eq(in2, in1);
    else if (in2.type == Q) {
      out = mpq_equal(in1.data.q, in2.data.q) != 0 ? true_data : false_data;
    } else if (in2.type == R) {
      mpf_t x;
      mpf_init(x);
      mpf_set_q(x, in1.data.q);
      out = mpf_cmp(x, in2.data.r) == 0 ? true_data : false_data;
      mpf_clear(x);
    } else
      out = error_data;
  } else if (in1.type == R) {
    if (in2.type == Z)
      out = number_eq(in2, in1);
    else if (in2.type == Q)
      out = number_eq(in2, in1);
    else if (in2.type == R) {
      out = mpf_cmp(in1.data.r, in2.data.r) == 0 ? true_data : false_data;
    } else
      out = error_data;
  } else
    out = error_data;
  return out;
}

static data_s number_less_than(data_s in1, data_s in2) {
  data_s out;
  if (in1.type == Z) {
    if (in2.type == Z) {
      out = mpz_cmp(in1.data.z, in2.data.z) < 0 ? true_data : false_data;
    } else if (in2.type == Q) {
      mpq_t x;
      mpq_init(x);
      mpq_set_z(x, in1.data.z);
      out = mpq_cmp(x, in2.data.q) < 0 ? true_data : false_data;
      mpq_clear(x);
    } else if (in2.type == R) {
      mpf_t x;
      mpf_init(x);
      mpf_set_z(x, in1.data.z);
      out = mpf_cmp(x, in2.data.r) < 0 ? true_data : false_data;
      mpf_clear(x);
    } else {
      out = error_data;
    }
  } else if (in1.type == Q) {
    if (in2.type == Z) {
      mpq_t x;
      mpq_init(x);
      mpq_set_z(x, in2.data.z);
      out = mpq_cmp(in1.data.q, x) < 0 ? true_data : false_data;
      mpq_clear(x);
    } else if (in2.type == Q) {
      out = mpq_cmp(in1.data.q, in2.data.q) < 0 ? true_data : false_data;
    } else if (in2.type == R) {
      mpf_t x;
      mpf_init(x);
      mpf_set_q(x, in1.data.q);
      out = mpf_cmp(x, in2.data.r) < 0 ? true_data : false_data;
      mpf_clear(x);
    } else {
      out = error_data;
    }
  } else if (in1.type == R) {
    if (in2.type == Z) {
      mpf_t x;
      mpf_init(x);
      mpf_set_z(x, in2.data.z);
      out = mpf_cmp(in1.data.r, x) < 0 ? true_data : false_data;
      mpf_clear(x);
    } else if (in2.type == Q) {
      mpf_t x;
      mpf_init(x);
      mpf_set_q(x, in2.data.q);
      out = mpf_cmp(in1.data.r, x) < 0 ? true_data : false_data;
      mpf_clear(x);
    } else if (in2.type == R) {
      out = mpf_cmp(in1.data.r, in2.data.r) < 0 ? true_data : false_data;
    } else {
      out = error_data;
    }
  } else {
    out = error_data;
  }
  return out;
}
#include "primitive_procedure.h"
#include <string.h>

data_s primitive_procedure_new(char *in) {
  return (data_s){.type = PRIMITIVE_PROCEDURE, .data.proc_name = strdup(in)};
}
void primitive_procedure_print(FILE *stream, data_s in) {
  fprintf(stream, "#<primitive-procedure %s>", in.data.proc_name);
}

bool is_primitive_procedure(data_s in) {
  return in.type == PRIMITIVE_PROCEDURE;
}

static GHashTable *prim_procs;
typedef data_s (*prim_proc_type)(data_s);
static void check_prim_proc_type(prim_proc_type pp) {}
#define prim_proc_hash_add(name, fn)                                           \
  {                                                                            \
    check_prim_proc_type(fn);                                                  \
    g_hash_table_insert(prim_procs, name, fn);                                 \
  }

data_s apply_primitive_procedure(data_s in1, data_s in2) {
  prim_proc_type pp = g_hash_table_lookup(prim_procs, in1.data.proc_name);
  return pp(in2);
}

#include "prim_list_procedures.h"
#include "prim_number_procedures.h"
void prim_proc_init() {
  prim_procs = g_hash_table_new(g_str_hash, g_str_equal);

  prim_proc_hash_add("car", prim_car);
  prim_proc_hash_add("cdr", prim_cdr);
  prim_proc_hash_add("set-car!", prim_set_car);
  prim_proc_hash_add("set-cdr", prim_set_cdr);
  prim_proc_hash_add("cons", prim_cons);
  prim_proc_hash_add("list", prim_list);
  prim_proc_hash_add("append", prim_append);
  prim_proc_hash_add("caar", prim_caar);
  prim_proc_hash_add("cadr", prim_cadr);
  prim_proc_hash_add("cdar", prim_cdar);
  prim_proc_hash_add("cddr", prim_cddr);
  prim_proc_hash_add("caar", prim_caar);
  prim_proc_hash_add("cadr", prim_cadr);
  prim_proc_hash_add("cdar", prim_cdar);
  prim_proc_hash_add("cddr", prim_cddr);
  prim_proc_hash_add("caaaar", prim_caaaar);
  prim_proc_hash_add("caaadr", prim_caaadr);
  prim_proc_hash_add("caadar", prim_caadar);
  prim_proc_hash_add("caaddr", prim_caaddr);
  prim_proc_hash_add("cadaar", prim_cadaar);
  prim_proc_hash_add("cadadr", prim_cadadr);
  prim_proc_hash_add("caddar", prim_caddar);
  prim_proc_hash_add("cadddr", prim_cadddr);
  prim_proc_hash_add("cdaaar", prim_cdaaar);
  prim_proc_hash_add("cdaadr", prim_cdaadr);
  prim_proc_hash_add("cdadar", prim_cdadar);
  prim_proc_hash_add("cdaddr", prim_cdaddr);
  prim_proc_hash_add("cddaar", prim_cddaar);
  prim_proc_hash_add("cddadr", prim_cddadr);
  prim_proc_hash_add("cdddar", prim_cdddar);
  prim_proc_hash_add("cddddr", prim_cddddr);

  prim_proc_hash_add("+", prim_number_add);
  prim_proc_hash_add("-", prim_number_sub);
  prim_proc_hash_add("*", prim_number_mul);
  prim_proc_hash_add("/", prim_number_div);
  prim_proc_hash_add("=", prim_number_eq);
  prim_proc_hash_add("<", prim_number_less_than);
}
#include "procedure.h"

#include "list_operations.h"
void procedure_print(FILE *stream, data_s in) {
  fprintf(stream, "#<procedure ");
  data_s_print(stream, car(in));
  fprintf(stream, " ");
  data_s_print(stream, cadr(in));
  fprintf(stream, ">");
}

bool is_procedure(data_s in) {
  return in.type == PROCEDURE ? true : false;
}

data_s make_procedure(data_s param, data_s body, data_s env) {
  data_s out = list(3, param, body, env);
  out.type = PROCEDURE;
  return out;
}
#include "quasiquote.h"

void quasiquote_print(FILE *stream, data_s in) {
  fprintf(stream, "#<syntax quasiquote>");
}

const data_s quasiquote_data = {.type = QUASIQUOTE};
#include "quote.h"
#include "evaluator.h"
#include "list_operations.h"

void quote_print(FILE *stream, data_s in) {
  fprintf(stream, "#<syntax quote>");
}

const data_s quote_data = {.type = QUOTE};
void ev_quoted() {
  data_s_free(val);
  val = data_s_copy(cadr(expr));
  /* cont.data.fn(); */
}
#include "repl.h"
#include "stack.h"
#include "kread.h"
#include "evaluator.h"
#include "environment.h"
#include "data.h"

static void print_result();

static void f() {}  
void read_eval_print_loop() {
  while (1) {
    initialize_stack();
    printf("kscm> ");
    expr = data_s_free(expr);
    expr = kread(stdin);
    env = global_environment;
    /* cont.data.fn = print_result; 変更 */
    /* cont.data.fn = f; */    
    eval_dispatch();  /* 追加 */

    print_result();
  }
}

static void print_result() {
  data_s_print(stdout, val);
  printf("\n");
  /* read_eval_print_loop(); */
}
#include "self_evaluating.h"
#include "evaluator.h"

bool is_self_evaluating(data_s in) {
  data_type type = in.type;
  return type == STRING || type == Z || type == Q || type == R;
}

void ev_self_eval() {
  val = data_s_free(val);
  val = data_s_copy(expr);
}
#include "sequence.h"

static void ev_sequence_cont();

#include "evaluator.h"
#include "data.h"
#include "list_operations.h"
#include "stack.h"

void ev_sequence() {
  expr = data_s_free(expr);
  expr = car(unev);
  if (cdr(unev).type == EMPTY) {
    /* eval_dispatch(); */
    eval_flag = 1;
  } else {
    save(unev);
    save(env);
    eval_dispatch();
    ev_sequence_cont();
  }
}

static void ev_sequence_cont() {
  env = restore();
  data_s_free(unev);
  unev = restore();
  unev = cdr(unev);
  ev_sequence();
}
#include "stack.h"
#include "list_operations.h"

static int number_pushes = 0;
static int max_depth = 0;
static int current_depth = 0;
#include "empty.h"
data_s stack;
void save(data_s in) {
  stack = cons(in, stack);
  number_pushes++;
  current_depth++;
  max_depth = max_depth > current_depth ? max_depth : current_depth;
}

data_s restore() {
  data_s t = car(stack);
  stack = cdr(stack);
  current_depth--;
  return t;
}

void initialize_stack() {
  number_pushes = 0;
  current_depth = 0;
  max_depth = 0;
  stack = empty_data;
}

void print_statistics() {
  printf(";(total-pushes = %d maximum-depth = %d\n", number_pushes,
         max_depth);
}
#include "string.h"
#include <string.h>
#include <stdlib.h>
#include "stopif.h"

data_s string_new(char *in) {
  char *s = strdup(in);
  Stopif(!s, exit(1), "メモリー不足");
  return (data_s){.type = STRING, .data.str = s};
}
data_s string_copy(data_s in) {
  char *s = strdup(in.data.str);
  Stopif(!s, exit(1), "メモリー不足");
  return (data_s){.type = STRING, .data.str = s};
}
void string_free(data_s in) {
  free(in.data.str);
  in.data.str = NULL;
}

#include <ctype.h>
void string_print(FILE *stream, data_s in) {
  fprintf(stream, "\"");
  char *s = in.data.str;
  while (*s != '\0') {
    if (isspace(*s)) {
      if (*s == ' ')
        fputc(' ', stream);
      else {
        fputc('\\', stream);
        if (*s == '\t')
          fputc('t', stream);
        else if (*s == '\n')
          fputc('n', stream);
        else if (*s == '\v')
          fputc('v', stream);
        else if (*s == '\f')
          fputc('f', stream);
        else if (*s == '\r')
          fputc('r', stream);
      }
    } else {
      fputc(*s, stream);
    }
    s++;
  }
  fprintf(stream, "\"");
}
#include "symbol.h"
#include <glib.h>
#include <string.h>

GHashTable *obarray;
data_s symbol_new(char *in) {
  char *s = g_hash_table_lookup(obarray, in);
  if (!s) {
    s = strdup(in);
    g_hash_table_insert(obarray, in, s);
  }
  return (data_s){.type = SYMBOL, .data.symbol = s};
}

void symbol_print(FILE *stream, data_s in) {
  fprintf(stream, "%s", in.data.symbol);
}

bool symbol_eq(data_s in1, data_s in2) {
  return in1.data.symbol == in2.data.symbol;
}

#include "boolean.h"
data_s is_symbol(data_s in) {
  return in.type == SYMBOL ? true_data : false_data;
}

#include "undef.h"

void undef_print(FILE *stream, data_s in) {
  fprintf(stream, "UNDEFINED");
}

const data_s undef = {.type=UNDEF};
#include "variable.h"
#include "evaluator.h"

bool is_variable(data_s in) {
  return in.type == SYMBOL;
}

#include "environment.h"
#include "error.h"
void ev_variable() {
  val = data_s_free(val);  
  val = lookup_variable_value(expr, env);
  if (val.type == ERROR)
    ev_error();
}

入出力結果(Terminal(kscm), REPL(Read, Eval, Print, Loop))

$ cat test.scm
(define fact
  (lambda (n)
    (if (= n 1)
        1
        (* n (fact (- n 1))))))

(define fib
  (lambda (n)
    (cond ((= n 0) 0)
          ((= n 1) 1)
          (#t (+ (fib (- n 1))
                 (fib (- n 2)))))))
    ;; (if (= n 0)
    ;;     0
    ;;     (if (= n 1)
    ;;         1
    ;;         (+ (fib (- n 1))
    ;;            (fib (- n 2)))))))

(fact 1000)

(fib 25)

(define fact
  (lambda (n)
    (define iter
      (lambda (n result)
        (if (= n 0)
            result
            (iter (- n 1) (* n result)))))
    (iter n 1)))

(fact 1000)
$ ./main < test.scm
kscm> #<procedure (n) ((if (= n 1) 1 (* n (fact (- n 1)))))>
kscm> #<procedure (n) ((cond ((= n 0) 0) ((= n 1) 1) (#t (+ (fib (- n 1)) (fib (- n 2))))))>
kscm> 402387260077093773543702433923003985719374864210714632543799910429938512398629020592044208486969404800479988610197196058631666872994808558901323829669944590997424504087073759918823627727188732519779505950995276120874975462497043601418278094646496291056393887437886487337119181045825783647849977012476632889835955735432513185323958463075557409114262417474349347553428646576611667797396668820291207379143853719588249808126867838374559731746136085379534524221586593201928090878297308431392844403281231558611036976801357304216168747609675871348312025478589320767169132448426236131412508780208000261683151027341827977704784635868170164365024153691398281264810213092761244896359928705114964975419909342221566832572080821333186116811553615836546984046708975602900950537616475847728421889679646244945160765353408198901385442487984959953319101723355556602139450399736280750137837615307127761926849034352625200015888535147331611702103968175921510907788019393178114194545257223865541461062892187960223838971476088506276862967146674697562911234082439208160153780889893964518263243671616762179168909779911903754031274622289988005195444414282012187361745992642956581746628302955570299024324153181617210465832036786906117260158783520751516284225540265170483304226143974286933061690897968482590125458327168226458066526769958652682272807075781391858178889652208164348344825993266043367660176999612831860788386150279465955131156552036093988180612138558600301435694527224206344631797460594682573103790084024432438465657245014402821885252470935190620929023136493273497565513958720559654228749774011413346962715422845862377387538230483865688976461927383814900140767310446640259899490222221765904339901886018566526485061799702356193897017860040811889729918311021171229845901641921068884387121855646124960798722908519296819372388642614839657382291123125024186649353143970137428531926649875337218940694281434118520158014123344828015051399694290153483077644569099073152433278288269864602789864321139083506217095002597389863554277196742822248757586765752344220207573630569498825087968928162753848863396909959826280956121450994871701244516461260379029309120889086942028510640182154399457156805941872748998094254742173582401063677404595741785160829230135358081840096996372524230560855903700624271243416909004153690105933983835777939410970027753472000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
kscm> 75025
kscm> #<procedure (n) ((define iter (lambda (n result) (if (= n 0) result (iter (- n 1) (* n result))))) (iter n 1))>
kscm> 402387260077093773543702433923003985719374864210714632543799910429938512398629020592044208486969404800479988610197196058631666872994808558901323829669944590997424504087073759918823627727188732519779505950995276120874975462497043601418278094646496291056393887437886487337119181045825783647849977012476632889835955735432513185323958463075557409114262417474349347553428646576611667797396668820291207379143853719588249808126867838374559731746136085379534524221586593201928090878297308431392844403281231558611036976801357304216168747609675871348312025478589320767169132448426236131412508780208000261683151027341827977704784635868170164365024153691398281264810213092761244896359928705114964975419909342221566832572080821333186116811553615836546984046708975602900950537616475847728421889679646244945160765353408198901385442487984959953319101723355556602139450399736280750137837615307127761926849034352625200015888535147331611702103968175921510907788019393178114194545257223865541461062892187960223838971476088506276862967146674697562911234082439208160153780889893964518263243671616762179168909779911903754031274622289988005195444414282012187361745992642956581746628302955570299024324153181617210465832036786906117260158783520751516284225540265170483304226143974286933061690897968482590125458327168226458066526769958652682272807075781391858178889652208164348344825993266043367660176999612831860788386150279465955131156552036093988180612138558600301435694527224206344631797460594682573103790084024432438465657245014402821885252470935190620929023136493273497565513958720559654228749774011413346962715422845862377387538230483865688976461927383814900140767310446640259899490222221765904339901886018566526485061799702356193897017860040811889729918311021171229845901641921068884387121855646124960798722908519296819372388642614839657382291123125024186649353143970137428531926649875337218940694281434118520158014123344828015051399694290153483077644569099073152433278288269864602789864321139083506217095002597389863554277196742822248757586765752344220207573630569498825087968928162753848863396909959826280956121450994871701244516461260379029309120889086942028510640182154399457156805941872748998094254742173582401063677404595741785160829230135358081840096996372524230560855903700624271243416909004153690105933983835777939410970027753472000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
kscm> $ 

0 コメント:

コメントを投稿