Rubyist Magazine - YARV Maniacs 【第 2 回】 VM ってなんだろうのVMをCで

ruby1.9のソース読もうかなーと思ったのでまずYARV Maniacsなど読んでます。で第二回のvmをc書いてみました。エラー処理とかはまったくしていません。

#include <stdio.h>

#define STACK_SIZE 30000

typedef enum Instruction Instruction;
typedef struct Code Code;
enum Instruction {
  I_PUSH, I_POP, I_DUP,
  I_ADD, I_SUB, I_MUL, I_DIV, I_NOT,
  I_JUMP, I_IF,
  I_EQ, I_LT, I_GT
};
struct Code {
  Instruction inst;
  int value;
};

int eval(Code program[], int program_len) {
  int stack[STACK_SIZE];
  int stack_index = 0;
  int pc;
  int x, y;

  for(pc=0;pc<program_len;++pc) {
    Code code = program[pc];
    switch(code.inst) {
      case I_PUSH:
        stack[stack_index++] = code.value;
        break;
      case I_POP:
        --stack_index;
        break;
      case I_DUP:
        x = stack[stack_index-1];
        stack[stack_index++] = x;
        break;
      case I_ADD:
        x = stack[--stack_index];
        stack[stack_index-1] += x;
        break;
      case I_SUB:
        x = stack[--stack_index];
        stack[stack_index-1] -= x;
        break;
      case I_MUL:
        x = stack[--stack_index];
        stack[stack_index-1] *= x;
        break;
      case I_DIV:
        x = stack[--stack_index];
        stack[stack_index-1] /= x;
        break;
      case I_NOT:
        x = stack[stack_index-1];
        stack[stack_index-1] = !x;
        break;
      case I_JUMP:
        pc = code.value-1;
        break;
      case I_IF:
        x = stack[--stack_index];
        if(x) {
          pc = code.value-1;
        }
        break;
      case I_EQ:
        x = stack[--stack_index];
        y = stack[stack_index-1];
        stack[stack_index-1] = x==y;
        break;
      case I_LT:
        x = stack[--stack_index];
        y = stack[stack_index-1];
        stack[stack_index-1] = x<y;
        break;
      case I_GT:
        x = stack[--stack_index];
        y = stack[stack_index-1];
        stack[stack_index-1] = x>y;
        break;
      default:
        break;
    }
  }
  return stack[0];
}
int main(int argc, char **argv) {
  Code program[] = {
    {I_PUSH, 1},
    {I_PUSH, 1},
    {I_ADD, 0},
    {I_DUP, 0},
    {I_PUSH, 100000},
    {I_GT, 0},
    {I_IF, 1}
  };
  int program_len = sizeof(program)/sizeof(Code);
  int result;
  result = eval(program, program_len);
  printf("%d\n", result);
  return 0;
}

実行結果

$ time ./a.out
100000
0.028 user 0.000 system 0.030 total

一瞬! えらい!

修正

I_EQ:のbreak書き忘れてたのだけ修正

test