• Coding
  • Exercise - Brainfuck Interpreter.

I always read all the codes that are posted on these exercises. I encourage all of you to do the same. But I disagree with non-spoiler times. It would kill certain threads super fast.
Yeah, I think it's OK to post as soon as you're done. No need for non-spoiler times :)
There's a special place in hell reserved for me for creating this code, but I'm posting it anyway!

This is a brainfuck interpreter. It waits for you to enter your brainfuck instructions, and when you press enter, it will execute them and print the output (if any), and then wait for your next instruction. I've written out each brainfuck symbol as its own function even though that's not really necessary, but I just wanted to leave room for some future meddling with the code. Everything else happens in the eval() function, which is almost identical to arithma's original code.

There's a lot of code repetition here the can be eliminated but I'm kind of lazy!

... Turing must be spinning in his grave.
#include <stdio.h>
#include <string.h>

#define INPUT_SIZE 1024
#define BF_BUFFER_SIZE 30000

unsigned char bf_buffer[BF_BUFFER_SIZE];
int bf_pointer;

void right() {
  bf_pointer = (bf_pointer + 1) % BF_BUFFER_SIZE;
}

void left() {
  bf_pointer = (bf_pointer - 1) % BF_BUFFER_SIZE;
}

void inc() {
  bf_buffer[bf_pointer]++;
}

void dec() {
  bf_buffer[bf_pointer]--;
}

void output() {
  printf("%c", bf_buffer[bf_pointer]);
}

void input() {
  bf_buffer[bf_pointer] = getchar();
}

int jz(char * buffer, int pointer) {
  if (bf_buffer[bf_pointer] == 0)
    while(++pointer < INPUT_SIZE)
      if (buffer[pointer] == ']')
	return pointer;
      return pointer;
}

int jnz(char * buffer, int pointer) {
  if (bf_buffer[bf_pointer] != 0)
    while(--pointer >= 0)
      if (buffer[pointer] == '[')
	return pointer;
      return pointer;
}

void eval(char * buffer)
{
  int input_pointer = 0;
  while (input_pointer < INPUT_SIZE) {
    switch (buffer[input_pointer]) {
      case '>': right();
      break;
      
      case '<': left();
      break;
      
      case '+': inc();
      break;
      
      case '-': dec();
      break;
      
      case '.': output();
      break;
      
      case ',': input();
      break;
      
      case '[': input_pointer = jz(buffer, input_pointer);
      break;
      
      case ']': input_pointer = jnz(buffer, input_pointer);
      break;
      
      case '\n':
	return;
	break;	
    }
    
    input_pointer++;
  }
}

int main(int argc, char * argv[])
{
  char buffer[INPUT_SIZE];
  memset(bf_buffer, 0, BF_BUFFER_SIZE);
  bf_pointer = 0;
  while (1) {
    printf("brainfuck:: ");
    fflush(stdout);
    if (fgets(buffer, INPUT_SIZE, stdin) == NULL)
      return 0;
    eval(buffer);
  }
  
  return 0;
}
saeidw wroteGoodness you code fast, arithma.
I second that. The specs of the language alone were enough to discourage me. Kudos to arithma.
@saeidw: Are you sure of your jz and jnz implementation? It does not seem to account for consecutive open brackets.
The way I understood it, the brainfuck interpreter must match the open brackets with closed ones. You seem to be just finding the first bracket of the other kind.
@arithma: you're right! I actually realized that when I was reading your code (the parse() function) but I completely ignored it when I was writing this, so I fell into that trap. Here are the fixed jz() and jnz() functions now with extra inner looping yumminess!
int jz(char * buffer, int pointer) {
    int inner = 1;
    int temp = pointer;
    while(++pointer < INPUT_SIZE) {
      if (buffer[pointer] == '[') inner++;
      if (buffer[pointer] == ']') {
	if (--inner == 0) break;
      }
    }
    if (inner != 0) {
      printf("Error: unmatched '['\n"); 
      pointer = INPUT_SIZE-1;
    }
    if (bf_buffer[bf_pointer] == 0) return pointer;
    return temp;
  }

  int jnz(char * buffer, int pointer) {
    int inner = 1;
    int temp = pointer;
    while(--pointer >= 0) {
      if (buffer[pointer] == ']') inner++;
      if (buffer[pointer] == '[') {
	if(--inner == 0) break;
      }
    }
    if (inner != 0) {
      printf("Error: unmatched ']'\n");
      pointer = INPUT_SIZE-1;
    }
    if (bf_buffer[bf_pointer] != 0) return pointer;
    return temp;
  }
PS: This exercise is particularly aimed at Padre who was complaining that my last exercises were too ... "beauty contest". Padre, I'm expecting to see your code here :)
ok ok , got it :P
just saw that :/, will code smth during the day.
int seek(char* buf, int p,int dir, char match, char umatch)
{
	int skip=0;
	while(1)
	{
		char cc=buf[p];
		if (buf[p]==umatch) skip++;
		if (buf[p]==match)
		{
			if (!skip) return p;
			if (skip) skip--;
		}
		p=p+dir;
	}
}

void bf(char *code)
{
	unsigned int p=0;
	unsigned int E=0;
	int bf_mem[BF_SIZE] = {0};

	while (code[E]!='\0')
	{
		switch (code[E])
		{
			case '+':
				bf_mem[p]++;
				break;
			case '-':
				bf_mem[p]--;
				break;
			case '>':
				p = p + 1 % BF_SIZE;
				break;
			case '<':
				p = p-1 % BF_SIZE;
				break;
			case '.':
				putchar(bf_mem[p]);
				break;
			case ',':
				bf_mem[p]=getchar();
				break;
			case '[':
				if(!bf_mem[p]) E=seek(code,E+1,1,']','[');
				break;
			case ']':
				if(bf_mem[p]) E=seek(code,E-1,-1,'[',']');
				break;
		  }
		E++;
	}
 }
this is my quick code. looks quite like arthima's code now that i compare them ... except that it doesn't have that sexy recursion :P
            case '>':
                p = p + 1 % BF_SIZE;
                break;
            case '<':
                p = p-1 % BF_SIZE;
                break;
% has higher precedence than + or -
This thing is bound to blow up.

I tried this code (which rahmu sent me). It worked well.
>++++++++++>+>+[
    [+++++[>++++++++<-]>.<++++++[>--------<-]+<<<]>.>>[
        [-]<[>+<-]>>[<<+>+>-]<[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-
            [>+<-[>+<-[>+<-[>[-]>+>+<<<-[>+<-]]]]]]]]]]]+>>>
    ]<<<
]
It's brainfucking amazing that it even avoids overflows!
5 years later
More fun in Go:
package main

import (
	"errors"
	"fmt"
	"log"
)

func matching_paren_up(code string, pos int) (int, error) {
	nr := 0
	for ; pos < len(code); pos += 1 {
		switch code[pos] {
		case '[':
			nr++
		case ']':
			nr--
			if nr < 0 {
				return pos, nil
			}
		}
	}
	return 0, errors.New("Couldn't match [")
}

func matching_paren_down(code string, pos int) (int, error) {
	nr := 0
	for pos -= 1; pos > 0; pos -= 1 {
		switch code[pos] {
		case ']':
			nr++
		case '[':
			nr--
			if nr < 0 {
				return pos, nil
			}
		}
	}
	return 0, errors.New("Couldn't match ]")
}

func bf(bf_code string) {
	data := make([]int, 30)
	ptr, idx := 0, 0
	var err error

	for ; idx < len(bf_code); idx += 1 {
		switch bf_code[idx] {
		case '+':
			data[ptr] += 1
		case '-':
			data[ptr] -= 1
		case '>':
			ptr = (ptr + 1) % 30000
		case '<':
			ptr = (ptr - 1) % 30000
		case '.':
			fmt.Printf("%c", data[ptr])
		case ',':
			fmt.Scanf("%c", data[ptr])
		case '[':
			if data[ptr] == 0 {
				idx, err = matching_paren_up(bf_code, idx)
			}
		case ']':
			if data[ptr] != 0 {
				idx, err = matching_paren_down(bf_code, idx)
			}
		}
		if err != nil {
			log.Fatal(err)
		}
	}
}

func main() {
	bf_helloworld := "++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>."
	bf(bf_helloworld)
}