2015年3月26日木曜日

開発環境

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

入れ子になったlambda式での変数探索の最適化のため、文面アドレスを実装。

参考書籍等

kscheme

コード(BBEdit, Emacs)

lexical_addressing.h

#pragma once
#include "data.h"

data_s lexical_address_lookup(data_s env, size_t frame_num, size_t disp_num);
data_s lexical_address_set(data_s env, size_t frame_num, size_t disp_num,
                           data_s val);
data_s find_variable(data_s var, data_s env);

lexical_addressing.c

#include "lexical_addressing.h"
#include "list_operations.h"
#include "data_structures.h"

data_s unassigned;
extern data_s error_data;
data_s lexical_address_lookup(data_s env, size_t frame_num, size_t disp_num) {
  data_s out = env;
  for (; frame_num > 0; frame_num--) {
    if (out.type == EMPTY) {
      fprintf(stderr, ";LEXICAL-ADDRESS-LOOKUP frame number: %ld displacement "
                      "number: %ld\n",
              frame_num, disp_num);
      return error_data;
    }
    out = enclosing_environment(out);
  }
  if (out.type == EMPTY) {
    fprintf(stderr, ";LEXICAL-ADDRESS-LOOKUP frame number: %ld displacement "
                    "number: %ld\n",
            frame_num, disp_num);
    return error_data;
  }

  out = first_frame(out);
  out = frame_values(out);
  for (; disp_num > 0; disp_num--)
    out = cdr(out);
  if (out.type == EMPTY) {
    fprintf(stderr, ";LEXICAL-ADDRESS-LOOKUP frame number: %ld displacement "
                    "number: %ld\n",
            frame_num, disp_num);
    return error_data;
  }

  out = car(out);
  return out.type == SYMBOL && out.data.symbol == unassigned.data.symbol
             ? error_data
             : out;
}

data_s lexical_address_set(data_s env, size_t frame_num, size_t disp_num,
                           data_s val) {
  data_s frame = env;
  for (; frame_num > 0; frame_num--) {
    if (frame.type == EMPTY) {
      fprintf(stderr, ";LEXICAL-ADDRESS-SET! frame number: %ld displacement "
                      "number: %ld\n",
              frame_num, disp_num);
      return error_data;
    }
    frame = enclosing_environment(frame);
  }
  if (frame.type == EMPTY) {
    fprintf(stderr, ";LEXICAL-ADDRESS-SET! frame number: %ld displacement "
                    "number: %ld\n",
            frame_num, disp_num);
    return error_data;
  }

  frame = car(frame);
  data_s values = frame_values(frame);
  for (; disp_num > 0; disp_num--) {
    if (values.type == EMPTY) {
      fprintf(stderr, ";LEXICAL-ADDRESS-SET! frame number: %ld displacement "
                      "number: %ld\n",
              frame_num, disp_num);
      return error_data;
    }
    values = cdr(values);
  }
  if (values.type == EMPTY) {
    fprintf(stderr, ";LEXICAL-ADDRESS-SET! frame number: %ld displacement "
                    "number: %ld\n",
            frame_num, disp_num);
    return error_data;
  }
  set_car(values, val);
  return val;
}

data_s not_found;
data_s find_variable(data_s var, data_s env) {
  size_t len = c_length(env);
  data_s frames = env;
  data_s frame;
  for (size_t frame_num = 0; frame_num < len; frame_num++) {
    frame = car(frames);
    frame = cdr(frame);
    size_t frame_len = c_length(frame);
    for (size_t disp_num = 0; disp_num < frame_len; disp_num++) {
      data_s b = is_eq(var, car(frame));
      if (b.type == SYMBOL && b.data.bln == true)
        return cons((data_s){.data.size = frame_num},
                    (data_s){.data.size = disp_num});
    }
  }
  return not_found;
}

kscheme.c

#include "kscheme.h"
#include "data.h"
#include "list_operations.h"

#include "expressions.h"
#include "data_structures.h"
#include "running_evaluator.h"

#include "lexical_addressing.h"
#include "kread.h"
#include <stdio.h>

void ev_appl_did_operator1();
void ev_appl_operand_first();
void ev_appl_operand_first_last();
void ev_appl_accum_first_arg();

extern data_s empty_data;
data_s expr, env, val, cont, proc, argl, unev;
/* 構文の型による場合分け */
void eval_dispatch() {
  if (is_self_evaluating(expr))
    ev_self_eval();
  else if (is_variable(expr))
    ev_variable();
  else if (is_quoted(expr))
    ev_quoted();
  else if (is_assignment(expr))
    ev_assignment();
  else if (is_definition(expr))
    ev_definition();
  else if (is_if(expr))
    ev_if();
  else if (is_lambda(expr))
    ev_lambda();
  else if (is_begin(expr))
    ev_begin();
  else if (is_application(expr))
    ev_application();
  else
    unknown_expression_type();
}

/* 単純式の評価 */
void ev_self_eval() {
  val = expr;
  cont.data.fn();
}

void ev_variable() {
  val = find_variable(expr, car(env));
  val = val.type == SYMBOL
            ? lookup_variable_value(expr, cdr(env))
            : lexical_address_lookup(cdr(env), car(val).data.size,
                                     cdr(val).data.size);
  cont.data.fn();
}

void ev_quoted() {
  val = text_of_quotation(expr);
  cont.data.fn();
}

void ev_lambda() {
  unev = lambda_parameters(expr);
  expr = lambda_body(expr);
  val = make_procedure(unev, expr, env);
  cont.data.fn();
}

/* 手続き作用の評価 */
void ev_application() {
  save(cont);
  unev = operands(expr);
  expr = operator(expr);
  if (expr.type == SYMBOL) {
    cont.data.fn = ev_appl_did_operator1;
  } else {
    cont.data.fn = ev_appl_did_operator;
    save(unev);
    save(env);
  }
  eval_dispatch();
}

void ev_appl_did_operator1() {
  proc = val;
  if (no_operands(unev)) {
    argl = empty_arglist();
    apply_dispatch();
  } else {
    save(proc);
    ev_appl_operand_first();
  }
}

void ev_appl_did_operator() {
  env = restore();
  unev = restore();
  proc = val;
  if (no_operands(unev)) {
    argl = empty_arglist();
    apply_dispatch();
  } else {
    save(proc);
    ev_appl_operand_first();
  }
}

void ev_appl_operand_first() {
  expr = first_operand(unev);
  if (is_last_operand(unev)) {
    cont.data.fn = ev_appl_operand_first_last;
    eval_dispatch();
  } else {
    save(env);
    save(unev);
    cont.data.fn = ev_appl_accum_first_arg;
    eval_dispatch();
  }
}

void ev_appl_operand_first_last() {
  argl = empty_arglist();
  argl = adjoin_arg(val, argl);
  proc = restore();
  apply_dispatch();
}

void ev_appl_accum_first_arg() {
  unev = restore();
  env = restore();
  argl = empty_arglist();
  argl = adjoin_arg(val, argl);
  unev = rest_operands(unev);
  ev_appl_operand_loop();
}

void ev_appl_operand_loop() {
  save(argl);
  expr = first_operand(unev);
  if (is_last_operand(unev))
    ev_appl_last_arg();
  else {
    save(env);
    save(unev);
    cont.data.fn = ev_appl_accumulate_arg;
    eval_dispatch();
  }
}

void ev_appl_accumulate_arg() {
  unev = restore();
  env = restore();
  argl = restore();
  argl = adjoin_arg(val, argl);
  unev = rest_operands(unev);
  ev_appl_operand_loop();
}

void ev_appl_last_arg() {
  cont.data.fn = ev_appl_accum_last_arg;
  eval_dispatch();
}

void ev_appl_accum_last_arg() {
  argl = restore();
  argl = adjoin_arg(val, argl);
  proc = restore();
  apply_dispatch();
}

/* 手続き作用 */
void apply_dispatch() {
  if (is_primitive_procedure(proc))
    primitive_apply();
  else if (is_compound_procedure(proc))
    compound_apply();
  else
    unknown_procedure_type();
}
void primitive_apply() {
  val = apply_primitive_procedure(proc, argl);
  cont = restore();
  cont.data.fn();
}
void compound_apply() {
  unev = procedure_parameters(proc);
  env = procedure_environment(proc);
  env = cons(cons(argl, car(env)),
             extend_environment(unev, argl, cdr(env)));
  unev = procedure_body(proc);
  ev_sequence();
}

/* 並びの評価 */
void ev_begin() {
  unev = begin_actions(expr);
  save(cont);
  ev_sequence();
}

void ev_sequence() {
  expr = first_expr(unev);
  if (is_last_expr(unev))
    ev_sequence_last_expr();
  else {
    save(unev);
    save(env);
    cont.data.fn = ev_sequence_cont;
    eval_dispatch();
  }
}

void ev_sequence_cont() {
  env = restore();
  unev = restore();
  unev = rest_exprs(unev);
  ev_sequence();
}

void ev_sequence_last_expr() {
  cont = restore();
  eval_dispatch();
}

/* 条件式 */
void ev_if() {
  save(expr);
  save(env);
  save(cont);
  cont.data.fn = ev_if_decide;
  expr = if_predicate(expr);
  eval_dispatch();
}
void ev_if_decide() {
  cont = restore();
  env = restore();
  expr = restore();
  if (val.type != BOOL || val.data.bln != false)
    ev_if_consequent();
  else
    ev_if_alternative();
}

void ev_if_alternative() {
  expr = if_alternative(expr);
  eval_dispatch();
}

void ev_if_consequent() {
  expr = if_consequent(expr);
  eval_dispatch();
}

/* 代入と定義 */
void ev_assignment() {
  unev = assignment_variable(expr);
  save(unev);
  expr = assignment_value(expr);
  save(env);
  save(cont);
  cont.data.fn = ev_assignment1;
  eval_dispatch();
}

void ev_assignment1() {
  cont = restore();
  env = restore();
  unev = restore();
  data_s lexical_address = find_variable(unev, car(env));
  if (lexical_address.type == SYMBOL)
    set_variable_value(unev, val, cdr(env));
  else
    lexical_address_set(cdr(env), car(lexical_address).data.size,
                        cdr(lexical_address).data.size, val);
  cont.data.fn();
}

void ev_definition() {
  unev = definition_variable(expr);
  save(unev);
  expr = definition_value(expr);
  save(env);
  save(cont);
  cont.data.fn = ev_definition1;
  eval_dispatch();
}

void ev_definition1() {
  cont = restore();
  env = restore();
  unev = restore();
  define_variable(unev, val, cdr(env));
  val = unev;
  cont.data.fn();
}

/* 評価の実行 */
void read_eval_print_loop() {
  initialize_stack();
  printf("In : ");
  expr = kread(stdin);
  env = get_global_environment();
  cont.data.fn = print_result;
  eval_dispatch();
}

void print_result() {
  printf("Out: ");
  user_print(val);
  print_statistics();
  read_eval_print_loop();
}

void unknown_expression_type() {
  data_s unknown_expression_type_error =
      symbol_new(";Unknown expression type error");
  val = unknown_expression_type_error;
  signal_error();
}

void unknown_procedure_type() {
  data_s unknown_procedure_type_error =
      symbol_new(";Unknown procedure type error");
  cont = restore();
  val = unknown_procedure_type_error;
  signal_error();
}
void signal_error() {
  user_print(val);
  read_eval_print_loop();
}

extern data_s *cars;
extern data_s *cdrs;
data_s *new_cars;
data_s *new_cdrs;

extern data_s root; /* garbage collection */
extern data_s stack;
extern data_s lambda;
extern data_s procedure;
extern data_s primitive;
extern data_s the_empty_environment;
extern data_s primitive_procedures;
extern data_s the_global_environment;
extern data_s compound_procedure;
extern data_s procedure_env;

/* lexical_addressing */
extern data_s unassigned;
extern data_s not_found;

int main() {
  cars = malloc(sizeof(data_s) * MEMORY_SIZE);
  cdrs = malloc(sizeof(data_s) * MEMORY_SIZE);
  new_cars = malloc(sizeof(data_s) * MEMORY_SIZE);
  new_cdrs = malloc(sizeof(data_s) * MEMORY_SIZE);

  expr = env = val = cont = proc = argl = unev = empty_data;
  lambda = symbol_new("lambda");
  procedure = symbol_new("procedure");
  primitive = symbol_new("primitive");
  compound_procedure = symbol_new("compound-procedure");
  procedure_env = symbol_new("<procedure-env>");
  the_empty_environment = empty_data;

  unassigned = symbol_new("*unassigned*");
  not_found = symbol_new("*not-found*");
  
  primitive_procedures =
      list(24, list(2, symbol_new("car"), (data_s){.type = CAR}),
           list(2, symbol_new("cdr"), (data_s){.type = CDR}),
           list(2, symbol_new("set!"), (data_s){.type = SET}),
           list(2, symbol_new("set-car!"), (data_s){.type = SET_CAR}),
           list(2, symbol_new("set-cdr!"), (data_s){.type = SET_CDR}),
           list(2, symbol_new("cons"), (data_s){.type = CONS}),
           list(2, symbol_new("eq?"), (data_s){.type = IS_EQ}),
           list(2, symbol_new("pair?"), (data_s){.type = IS_PAIR}),
           list(2, symbol_new("null?"), (data_s){.type = IS_NULL}),
           list(2, symbol_new("symbol?"), (data_s){.type = IS_SYMBOL}),
           list(2, symbol_new("number?"), (data_s){.type = IS_NUMBER}),
           list(2, symbol_new("char?"), (data_s){.type = IS_CHAR}),
           list(2, symbol_new("string?"), (data_s){.type = IS_STRING}),
           list(2, symbol_new("map"), (data_s){.type = MAP}),
           list(2, symbol_new("list"), (data_s){.type = LIST}),
           list(2, symbol_new("+"), (data_s){.type = NUMBER_ADD}),
           list(2, symbol_new("-"), (data_s){.type = NUMBER_SUB}),
           list(2, symbol_new("*"), (data_s){.type = NUMBER_MUL}),
           list(2, symbol_new("/"), (data_s){.type = NUMBER_DIV}),
           list(2, symbol_new("="), (data_s){.type = NUMBER_EQ}),
           list(2, symbol_new("<"), (data_s){.type = NUMBER_LESS_THAN}),
           list(2, symbol_new("display"), (data_s){.type = DISPLAY}),
           list(2, symbol_new("newline"), (data_s){.type = NEWLINE}),
           list(2, symbol_new("exit"), (data_s){.type = EXIT}));
  the_global_environment = setup_environment();
  read_eval_print_loop();
}

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

$ ./kscheme 
In : (define f
  ((lambda (x y)
     (lambda (a b c d e)
            ((lambda (y z) (* x y))
             (* x y)
             (+ x y))))
   1
   2))
Out: f
;(total-pushes = 10 maximum-depth = 7)
In : f
Out: (compound-procedure (a b c d e) (((lambda (y z) (* x y)) (* x y) (+ x y))) <procedure-env>)
;(total-pushes = 0 maximum-depth = 0)
In : (f 1 2 3 4 5)
Out: 2
;(total-pushes = 36 maximum-depth = 8)
In : (exit)
$

0 コメント:

コメントを投稿