Почему инструкции [ и ] не работают в этой реализации интерпретатора Brainfrick?

Приведенный ниже код представляет собой черновую реализацию интерпретатора Brainfrick на Java. Спецификации, которые я использую, следующие:

Команды Brainfuck

>   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.

Все инструкции работают нормально, кроме инструкций [ и ]. Петли просто не работают. Я пробовал отладку с помощью ручки и бумаги, но вроде все нормально. Язык спецификаций говорит о переходе вперед после сопоставления ] (то есть неявно следующего ]), который я реализую с помощью циклов for, аналогично механизму перехода назад.

Вопрос: Почему реализация демонстрирует нежелательное поведение?

Редактировать 1: я добавил подход использования счетчика для увеличения при обнаружении открытия [ и уменьшения при достижении a ]. но ошибка все еще сохраняется.

Редактировать 2: код теперь работает нормально, включая циклы, но вывод в терминале Windows показывает вопросительные знаки вместо hello world. что может быть причиной этого?

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();
    }  
} 

как и просили, код, который я пытаюсь запустить, представляет собой некомментированную версию hello world со страницы языка в Википедии.

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

🤔 А знаете ли вы, что...
Java активно развивается и обновляется с появлением новых версий и функциональных улучшений.


72
1

Ответ:

Решено

в обновленной реализации есть несколько небольших ошибок, поэтому вот один из возможных способов сделать это правильно:

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;