javainterpreter

Why does the [ and ] instructions not work in this Brainfrick interpreter implementation?


The code below is a rough cut implementation of the brainfrick interpreter in Java. The specs I'm using are as follows:

Brainfuck commands

>   Increment the pointer.

<   Decrement the pointer.

+   Increment the byte at the pointer.

-   Decrement the byte at the pointer.

.   Output the byte at the pointer.

,   Input a byte and store it in the byte at the pointer.

[   Jump forward past the matching ] if the byte at the pointer is zero.

]   Jump backward to the matching [ unless the byte at the pointer is zero.

The instructions work fine all except the [ and the ] instructions. The loops simply don't work. I've tried pen and paper debugging but it seems fine. The language of the specs say jump forward past the matching ] (implicitly the next ] that is) which i implement using the for loops, similarly for the jump backward mechanism.

Question : Why is the implementation exhibiting unwanted behaviour?

Edit 1 : I have added the approach of using a counter to increment when an opening [ is met and decrement when a ] is met. but the error still persists.

Edit 2 : The code now works fine, including the loops, but the output in the windows terminal shows question marks instead of hello world. what could be the cause behind this?

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;

class Brainfrick {

    public static boolean isValid(char command) {
        switch (command) {
            case '>':
            case '<':
            case '+':
            case '-':
            case '.':
            case ',':
            case '[':
            case ']':
                return true;
            default:
                return false;
        }
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String file = System.getProperty("user.dir") + "\\" + args[0];
        //System.out.println(file);
        String content = "";
        try {
            content = Files.readString(Paths.get(file));
        } catch (Exception e) {
            System.out.println("Error reading the file! Printing the stack trace of JVM");
            e.printStackTrace();
            System.exit(-1);
        }
        final char[] commands = content.toCharArray();
        int[] tape = new int[30000];
        int ptr = 0;
        //Stack<Integer> loopStack = new Stack<>();
        int i = 0, ctr = 0;
        while(i < commands.length) {
            char command = commands[i];
            if (!isValid(command)) continue;
            switch (command) {
                case '>':
                    ptr++;
                    i++;
                    break;
                case '<':
                    ptr--;
                    i++;
                    break;
                case '+':
                    tape[ptr]++;
                    i++;
                    break;
                case '-':
                    tape[ptr]--;
                    i++;
                    break;
                case '.':
                    System.out.print((char)tape[ptr]);
                    i++;
                    break;
                case ',':
                    int x = sc.nextInt();
                    sc.nextLine();
                    tape[ptr] = x;
                    i++;
                    break;
                case '[':
                    if (tape[ptr] == 0) {
                         ctr = 0;
                         for(;ctr != 0; ++i){
                            if(commands[i] == '[') ctr+= 1;
                            else if(commands[i] == ']') ctr -= 1;
                        }
                         i++;
                        }
                    i++;
                    break;
                case ']':
                    ctr = 0;
                    if (tape[ptr] != 0) {
                       for(;ctr != 0; --i){
                        if(commands[i] == '[') ctr+= 1;
                            else if(commands[i] == ']') ctr -= 1;
                        }
                    }
                    i++; 
                    break;
                default:
                    continue;
            }
        }
        sc.close();
    }  
} 

as requested, the code im trying to run is the uncommented version of hello world from wikipedia page of the language

++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.

Solution

  • there are multiple small errors in updated implementation, so here is one of the possible ways to do this correctly:

    case '[':
        if (tape[ptr] == 0) {
            ctr = 0;
            do {
                ctr += commands[i]=='['?1:0;
                ctr -= commands[i]==']'?1:0;
                i++;
            } while (ctr > 0);
        } else
            i++;
        break;
    case ']':
        if (tape[ptr] != 0) {
            ctr = 0;
            do {
                ctr -= commands[i]=='['?1:0;
                ctr += commands[i]==']'?1:0;
                i--;
            } while (ctr > 0);
        }
        i++;
        break;