Skip to content

Instantly share code, notes, and snippets.

@keiya
Created August 2, 2014 07:39
Show Gist options
  • Select an option

  • Save keiya/5788a526dc46ea85fff5 to your computer and use it in GitHub Desktop.

Select an option

Save keiya/5788a526dc46ea85fff5 to your computer and use it in GitHub Desktop.
// BrainFsck Ruby Extension by Keiya CHINEN <[email protected]>
// C extension and Ruby src was written by Keiya CHINEN <[email protected]>
// Original version (Pure-C): https://github.com/keiya/brainfuck
#include "ruby.h"
#include <stdio.h>
#include <stdlib.h>
char *prog;
int ary[30000];
int *ptr = ary;
int idx;
int stack[100];
int stack_flag[100];
int stack_idx = 0;
void brainfsck();
void
init()
{
int i;
for (i=0;i<100;i++) {
stack[i] = 0;
stack_flag[i] = 0;
}
}
void
push(int val,int flag)
{
if (stack_idx < 100) {
stack[stack_idx++] = val;
stack_flag[stack_idx] = flag;
}
else {
fprintf(stderr,"stack overflow");
exit(EXIT_FAILURE);
}
}
int
pop()
{
if (stack_idx > 0) {
int tmp = stack[--stack_idx];
return tmp;
}
else {
fprintf(stderr,"stack underflow");
exit(EXIT_FAILURE);
}
}
int
check()
{
int i;
return stack_flag[stack_idx];
}
int
interpret(int startidx)
{
int ch = prog[idx];
switch (ch) {
case '>':
idx++;
if (check()) break;
ptr++;
break;
case '<':
idx++;
if (check()) break;
ptr--;
break;
case '+':
idx++;
if (check()) break;
(*ptr)++;
break;
case '-':
idx++;
if (check()) break;
(*ptr)--;
break;
case '.':
idx++;
if (check()) break;
//putchar(*ptr);
rb_funcall(rb_mKernel, rb_intern("print"),1, rb_str_new_cstr(ptr));
fflush(stdout);
break;
case ',':
idx++;
if (check()) break;
//*ptr = getchar();
VALUE str = rb_funcall(rb_stdin, rb_intern("getc"),0);
strncpy(ptr, StringValueCStr(str), 1);
//*ptr = StringValueCStr(str);
break;
case '[':
if (*ptr == 0) {
push(idx,1);
idx++;
}
else {
push(idx,0);
idx++;
}
break;
case ']':
if (check() != 1) {
idx = pop();
}
else {
pop();
idx++;
}
break;
case '\0':
return 0;
default:
idx++;
break;
}
return 1;
}
VALUE exec(VALUE self, VALUE bf)
{
char *str = StringValueCStr(bf);
init();
unsigned long sz = strlen(str);
int i;
for (i=0; i<30000; i++)
ary[i] = 0;
if (NULL == (prog = (char *)malloc(sz))) {
fprintf(stdout,"malloc\n");
exit(EXIT_FAILURE);
}
strcpy(prog,str);
fflush(stdin);
idx = 0;
while(interpret(0)) {
}
return Qnil;
}
void Init_brainfsck(void){
VALUE rb_cBf;
rb_cBf = rb_define_class("BrainFsck", rb_cObject);
rb_define_method(rb_cBf, "exec", exec, 1);
}
# BrainFsck
# C extension and Ruby src was written by Keiya CHINEN <[email protected]>
# brainf*ck test code by http://www.kmonos.net/alang/etc/brainfuck.php
require_relative "brainfsck.bundle"
bf = BrainFsck.new
# Hello World!
d = bf.exec(">+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.[-]>++++++++[<++++>-]<.>+++++++++++[<+++++>-]<.>++++++++[<+++>-]<.+++.------.--------.[-]>++++++++[<++++>-]<+.[-]++++++++++.")
puts()
# Hoge
bf.exec("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.+++++++.--------.--.")
puts()
# Hoge (uses loop)
bf.exec("++++++++++[>++++++++++<-]>++++.+++++++.--------.--.");
puts()
# Hello World! (alternative way)
bf.exec("++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.")
puts()
# Multiply
puts("4*2=")
bf.exec("++++>++><<[- >[->>+<<] >>[-<+<+>>] <<<]>>++++++++++++++++++++++++++++++++++++++++++++++++.")
puts()
# conditional test (uppercase to lowercase)
puts("Upper Case to Lower Case. please input :")
bf.exec(<<-eos
### init: ##################################
>>++++++++[->++++++++<]> # {3} = 0x40
>>>+++++++++[->++++++++++<]> # {7} = 0x5A ptr=7
### main: ##################################
[<<, # {5} = getchar()
## 00 00 00 40 00 *ch 00 5A 00 00 00
[->+<<+<<+>>>] # {2:4:6} = !{5}
<<<[->>>+<<<]>>> # {5} = !{2}
## 00 00 00 40 ch *ch ch 5A 00 00 00
>>[->+>>+<<<]> # {8:10} = !{7}
## 00 00 00 40 ch ch ch 00 *5A 00 5A
[ # while( {8} ) do
<<[->+>>+<<<]>> # {7:9} = !{6}
>[-<<<+>>>]< # {6} = !{9}
<[[-]<->]> # if({7}) then decr{6}
- # decr {8}
] # end
>>[-<<<+>>>]<<<<< # {7} = !{10}
## 00 00 00 40 ch *ch ans1 5A 00 00 00
## ans1 = 0 iff input le 5A
<<[-<+<<+>>>]< # {0:2} = !{3}
## 40 00 *40 00 ch ch ans1 5A 00 00 00
[ # while( {2} ) do
>>[-<+<<+>>>]<< # {1:3} = !{4}
<[->>>+<<<]> # {4} = !{1}
>[[-]>-<]< # if({3}) then decr{4}
- # decr {2}
] # end
<<[->>>+<<<]>>>>> # {3} = !{0}
## 00 00 00 40 ans2 *ch ans1 5A 00 00 00
## ans2 = 0 iff input le 40
# if(ans2) if(not ans1) {5} add 0x20
<[[-] # if( {4} ) then do
>++++++++++++++++++++++++++++++++ # {5} add 0x20
>[[-] # if( !{6} ) then do
<--------------------------------> # {5} sub 0x20
]<< # end
]>>[-]< # end; !{6}
## 00 00 00 40 00 *ch 00 5A 00 00 00
.>>] # putchar {5}
eos
)
# echo (gets from STDIN => puts to STDOUT)
#bf.exec("+[>,.<]")
require 'mkmf'
create_makefile('brainfsck')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment