Sfoglia il codice sorgente

feat: BrainFuckPro 第一版本

实现了BrainFuck的基本功能
添加了BrainFuckPro特色语法
添加了make install安装程序
添加了命令行参数处理模块
添加了命令行模式
SongZihuan 3 anni fa
commit
1788a4836a
9 ha cambiato i file con 739 aggiunte e 0 eliminazioni
  1. 59 0
      .gitignore
  2. 21 0
      CMakeLists.txt
  3. 21 0
      LICENSE
  4. 72 0
      README.md
  5. 30 0
      include/brainfuck.h
  6. 144 0
      main.c
  7. 5 0
      src/CMakeLists.txt
  8. 44 0
      src/_brainfuck.h
  9. 343 0
      src/brainfuck.c

+ 59 - 0
.gitignore

@@ -0,0 +1,59 @@
+# C Language
+# Prerequisites
+*.d
+
+# Object files
+*.o
+*.ko
+*.obj
+*.elf
+
+# Linker output
+*.ilk
+*.map
+*.exp
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Libraries
+*.lib
+*.a
+*.la
+*.lo
+
+# Shared objects (inc. Windows DLLs)
+*.dll
+*.so
+*.so.*
+*.dylib
+
+# Executables
+*.exe
+*.out
+*.app
+*.i*86
+*.x86_64
+*.hex
+
+# Debug files
+*.dSYM/
+*.su
+*.idb
+*.pdb
+
+# Kernel Module Compile Results
+*.mod*
+*.cmd
+.tmp_versions/
+modules.order
+Module.symvers
+Mkfile.old
+dkms.conf
+
+#IDE
+.idea
+.vs
+.vscode
+cmake-*

+ 21 - 0
CMakeLists.txt

@@ -0,0 +1,21 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 3.19)
+SET(CMAKE_C_STANDARD 11)
+PROJECT(BrainFuck C)
+
+ADD_DEFINITIONS(-DBF_VERSION="1.0.0 Version")
+ADD_DEFINITIONS(-DBF_VERSION_INFO="first version of BrainFuckPro")
+
+SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY bin)
+SET(LIBRARY_OUTPUT_PATH lib)  # 设置输出路径
+SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH})
+SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH})
+
+SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")  # 设定rpath
+
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include)
+
+ADD_SUBDIRECTORY(${CMAKE_SOURCE_DIR}/src)
+ADD_EXECUTABLE(BrainFuck main.c)
+TARGET_LINK_LIBRARIES(BrainFuck BrainFuck_Lib)
+
+INSTALL(TARGETS BrainFuck BrainFuck_Lib)

+ 21 - 0
LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2021 SuperHuan
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 72 - 0
README.md

@@ -0,0 +1,72 @@
+# BrainFuck Pro
+使用C语言实现的BrainFuck解释器,并且扩展了部分语法。
+## 关于BrainFuck
+Brainfuck,是一种极小化的程序语言,它是由Urban Müller在1993年创造的。这种语言有时被简称为BF。
+## 命令函参数
+```
+使用: BrainFuck[参数] 文件..  
+参数:  
+-e --eval              从一个字符串中运行代码  
+-v --version           显示版本信息  
+-h --help              显示帮助信息  
+```
+##支持的语法
+```
+使用:指令[指令[指令...]]
+指令
+>       读取头向后移动1格
+<       读取头向前移动1格
++       读取头所指格子的数据增加1
+-       读取头所指格子的写入数据减1
+
+>n      读取头向后移动n格
+<n      读取头向前移动n格
++n      读取头所指格子的数据增加n
+-n      读取头所指格子的写入数据减n
+
+.       输出读取头所指格子的数据(字符形式)
+,       对读取头所指格子的写入数据(字符形式)
+:       输出读取头所指格子的数据(数字形式)
+;       对读取头所指格子的写入数据(数字形式)
+
+[       循环初始位置(若读取头所指格子的数据不为0则循环)
+]       循环结束位置
+?       读取头回到初始位置
+```
+
+##命令行模式
+执行完成指定文件后,BrainFuckPro进入命令行交互模式。使用者可以通过stdin即时写入指令操控读取头。
+##关于API
+BrainFuckPro为C语言提供了相应的API。若需要使用,请链接库`BrainFuck_LIB`和包含头文件`brainfuck.h`。  
+```c
+char *bf_getVersionInfo();  // 获取版本和版本信息字符串
+char *bf_getVersion();  // 获取版本
+
+// bf_env指针通常可以使用void *来代替
+bf_env *bf_setEnv();  // 设置一个运行环境(返回一个指针)
+void bf_freeEnv(bf_env *env);  // 释放一个环境
+void bf_initEnv(bf_env *env);  // 复位读取头到初始位置
+
+// bf_code指针通常可以使用void *来代替
+void bf_freeBrainFuck(bf_code code);  // 释放代码
+bf_code bf_parserBrainFuck_File(FILE *file);  // 读取文件并生成代码(返回一个code)
+bf_code bf_parserBrainFuck_Str(const char *str); // 读取字符串并生成代码(返回一个code)
+void bf_printBrainFuck(bf_code code); // 打印代码
+int bf_runBrainFuck(bf_code code, bf_env *env); // 在指定环境中执行代码 (返回0表示无异常)
+void bf_printError(char *info, bf_env *env);  // 打印错误信息, 若无错误则不执行
+```
+`bf_env`即图灵机的纸带,`bf_code`即读取头的指令。二者本质上均为指针,且在brainfuck.h中无具体实现,使用者可以使用`void *`来代替。
+##构建
+使用cmake+make来构建本项目。
+cmake中可以设置`CMAKE_INSTALL_PREFIX`指定文件安装路径。
+可以使用`make`构建项目,使用`make install`安装项目。
+##声明
+###版权声明
+版权所有 © 2021 [SuperHuan](https://github.com/SuperH-0630) 保留所有权利。  
+BrainFuckPro编程语言C解释器由SuperHuan开发,技术归属SuperHuan。  
+本授权协议适用于BrainFuckPro编程语言C解释器,SuperHuan拥有对本授权协议最终解释权和修改权。  
+###免责声明
+BrainFuckPro编程语言C解释器为免费开源程序。  
+编译、运行该程序过程中造成的损失(包括但不限于系统损坏、文件丢失)均由您个人承担, 与开发者无关。
+###LICENSE
+该代码是在 MIT License 下发布的。

+ 30 - 0
include/brainfuck.h

@@ -0,0 +1,30 @@
+#ifndef BRAINFUCK_BRAINFUCK_H
+#define BRAINFUCK_BRAINFUCK_H
+
+#ifndef TYPEDEF_bf_code
+typedef struct bf_code *bf_code;
+#define TYPEDEF_bf_code
+#endif
+
+#ifndef TYPEDEF_bf_env
+typedef struct bf_env bf_env;
+#define TYPEDEF_bf_env
+#endif
+
+char *bf_getVersionInfo();  // 获取版本和版本信息字符串
+char *bf_getVersion();  // 获取版本
+
+// bf_env指针通常可以使用void *来代替
+bf_env *bf_setEnv();  // 设置一个运行环境(返回一个指针)
+void bf_freeEnv(bf_env *env);  // 释放一个环境
+void bf_initEnv(bf_env *env);  // 复位读取头到初始位置
+
+// bf_code指针通常可以使用void *来代替
+void bf_freeBrainFuck(bf_code code);  // 释放代码
+bf_code bf_parserBrainFuck_File(FILE *file);  // 读取文件并生成代码(返回一个code)
+bf_code bf_parserBrainFuck_Str(const char *str); // 读取字符串并生成代码(返回一个code)
+void bf_printBrainFuck(bf_code code); // 打印代码
+int bf_runBrainFuck(bf_code code, bf_env *env); // 在指定环境中执行代码 (返回0表示无异常)
+void bf_printError(char *info, bf_env *env);  // 打印错误信息, 若无错误则不执行
+
+#endif //BRAINFUCK_BRAINFUCK_H

+ 144 - 0
main.c

@@ -0,0 +1,144 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <string.h>
+
+#include "brainfuck.h"
+#define COMMAND_LINE_STR_SIZE (20)
+
+static struct option long_options[] = {
+        {"version", no_argument, 0, 'v'},
+        {"help", no_argument, 0, 'h'},
+        {"eval", required_argument, 0, 'e'},
+        {0, 0, 0, 0}
+};
+
+void printUsage(char *name) {
+    printf("Usage: %s[options] file..\n", name);
+    printf("Options: \n");
+    printf(" -e --eval\t\tRun code in a string\n");
+    printf(" -v --version\t\tshow version\n");
+    printf(" -h --help\t\tshow help\n\n");
+
+    printf("\nFor more information, please see: \n");
+    printf("github.com/SuperH-0630/BranchFuckPro\n");
+}
+
+void printVersion() {
+    printf("%s", bf_getVersionInfo());
+}
+
+int runFile(int argc, char **argv, bf_env *env) {
+    while (optind < argc) {
+        FILE *file = fopen(argv[optind], "r");
+
+        if (file == NULL) {
+            perror("read file error");
+            return 1;
+        }
+
+        bf_code code;
+        code = bf_parserBrainFuck_File(file);
+        bf_runBrainFuck(code, env);
+        bf_printError("run error", env);
+        bf_initEnv(env);
+        bf_freeBrainFuck(code);
+        fclose(file);
+
+        optind++;
+    }
+    return 0;
+}
+
+int runCommandLine_(bf_env *env) {
+    int size = COMMAND_LINE_STR_SIZE;
+    int status;
+    char *str = calloc(size + 1, sizeof(char ));
+    fgets(str, COMMAND_LINE_STR_SIZE + 1, stdin);
+    while (!strchr(str, '\n') && !feof(stdin) && !ferror(stdin)) {
+        char *new = calloc(size + COMMAND_LINE_STR_SIZE + 1, sizeof(char ));
+        strcpy(new, str);
+        fgets(new + size, COMMAND_LINE_STR_SIZE + 1, stdin);
+        free(str);
+        str = new;
+        size += COMMAND_LINE_STR_SIZE;
+    }
+
+    bf_code code;
+    code = bf_parserBrainFuck_Str(str);
+    status = bf_runBrainFuck(code, env);
+    bf_printError("command line error", env);
+    bf_freeBrainFuck(code);
+    free(str);
+    return status;
+}
+
+int runCommandLine(bf_env *env) {
+    int ch;
+    unsigned int count = 0;
+
+    printf("BranchFuck %s (" __DATE__ ", " __TIME__ ")\n", bf_getVersion());
+    printf("Welcome to ues BranchFuck CommandLine (Type 'q' to quit)\n");
+
+    while (1) {
+        if (feof(stdin) || ferror(stdin))
+            return 1;
+        printf("[%d] >", count);
+        ch = getc(stdin);
+        if (ch == 'q')
+            return 0;
+        else
+            ungetc(ch, stdin);
+        runCommandLine_(env);
+        count++;
+    }
+}
+
+int main(int argc, char **argv){
+    int option_index = 0;
+    int status;
+    bf_env *env = bf_setEnv();
+
+    while (1) {
+        option_index = 0;
+        int c = getopt_long (argc, argv, "vhe:", long_options, &option_index);
+        if (c == -1)
+            break;
+
+        switch (c) {
+            case 0:
+                break;
+            case 'h':
+                printUsage(argv[0]);
+                return 0;
+            case 'v':
+                printVersion();
+                return 0;
+            case 'e': {
+                bf_code code;
+                code = bf_parserBrainFuck_Str((char *) optarg);
+                bf_runBrainFuck(code, env);
+                bf_printError("eval error", env);
+                bf_freeBrainFuck(code);
+                break;
+            }
+            default:
+            case '?':
+                printUsage(argv[0]);
+                return 1;
+        }
+    }
+
+    status = runFile(argc, argv, env);
+    if (status != 0)
+        return status;
+
+    status = runCommandLine(env);
+    if (status == 1) {
+        printf("stdin error\n");
+        return status;
+    }
+
+    printf("BranchFuckPro: bye~\n");
+    return 0;
+}

+ 5 - 0
src/CMakeLists.txt

@@ -0,0 +1,5 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 3.19)
+SET(CMAKE_C_STANDARD 11)
+PROJECT(BrainFuck_Lib C)
+
+ADD_LIBRARY(BrainFuck_Lib SHARED brainfuck.c)

+ 44 - 0
src/_brainfuck.h

@@ -0,0 +1,44 @@
+#ifndef BRAINFUCK__BRAINFUCK_H
+#define BRAINFUCK__BRAINFUCK_H
+
+#define TABLE_SIZE (20)
+#define FILE_READ_SIZE (20)
+
+typedef char *bf_byte;
+typedef struct bf_item bf_item;
+typedef struct bf_pitem bf_pitem;
+typedef struct bf_env bf_env;
+
+#ifndef TYPEDEF_bf_env
+typedef struct bf_env bf_env;
+#define TYPEDEF_bf_env
+#endif
+
+#ifndef TYPEDEF_bf_code
+typedef struct bf_code *bf_code;
+#define TYPEDEF_bf_code
+#endif
+
+struct bf_code {
+    bf_byte byte;
+};
+
+struct bf_item {
+    int data[TABLE_SIZE];
+    struct bf_item *prev;
+    struct bf_item *next;
+};
+
+struct bf_pitem {
+    int index;
+    struct bf_item *item;
+    struct bf_item *base;
+};
+
+struct bf_env {
+    struct bf_item *item;
+    struct bf_pitem pitem;
+    char *error_info;  // 错误信息 (字符串常量)
+};
+
+#endif //BRAINFUCK__BRAINFUCK_H

+ 343 - 0
src/brainfuck.c

@@ -0,0 +1,343 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+
+#include "brainfuck.h"
+#include "_brainfuck.h"
+
+#ifndef BF_VERSION
+#define BF_VERSION "Magic Version"
+#define BF_VERSION_INFO "This is a magical version because no one knows how magical he is."
+#endif
+
+char *bf_getVersionInfo() {
+    return BF_VERSION "\n" BF_VERSION_INFO "\n";
+}
+
+char *bf_getVersion() {
+    return BF_VERSION;
+}
+
+static bf_code make_bf_code() {
+    bf_code code = calloc(1, sizeof(struct bf_code));
+    return code;
+}
+
+static void free_bf_code(bf_code code) {
+    free(code->byte);
+    free(code);
+}
+
+void bf_freeBrainFuck(bf_code code) {
+    free_bf_code(code);
+}
+
+bf_code bf_parserBrainFuck_Str(const char *str) {
+    char ch;
+    int size = FILE_READ_SIZE;
+    int index = 0;
+    int str_index = 0;
+    bf_code code = make_bf_code();
+    code->byte = calloc(FILE_READ_SIZE + 1, sizeof(bf_byte));
+
+    while ((ch = str[str_index++]) != '\0'){
+        if (ch == '@') {  // 注释语句(忽略所有到行末, 或同行的@)
+            while ((ch = str[str_index++]) != '\n' && ch != '@' && ch != '\0')
+                continue;
+            continue;
+        } else if (ch != '>' && ch != '<' &&
+                   ch != '.' && ch != ',' &&
+                   ch != '+' && ch != '-' &&
+                   ch != ':' && ch != ';' &&
+                   ch != '[' && ch != ']' &&
+                   ch != '?' &&!isalnum(ch)) {
+            continue;  // 其他内容也被忽略
+        }
+
+        if (index > size) {
+            bf_byte byte = calloc(size + FILE_READ_SIZE + 1, sizeof(bf_byte));
+            strcpy(byte, code->byte);
+            free(code->byte);
+            code->byte = byte;
+        }
+
+        code->byte[index] = (char)ch;
+        index++;
+    }
+
+    return code;
+}
+
+bf_code bf_parserBrainFuck_File(FILE *file) {
+    int ch;
+    int size = FILE_READ_SIZE;
+    int index = 0;
+    bf_code code = make_bf_code();
+    code->byte = calloc(FILE_READ_SIZE + 1, sizeof(bf_byte));
+
+    while ((ch = getc(file)) != EOF){
+        if (ch == '@') {  // 注释语句(忽略所有到行末, 或同行的@)
+            while ((ch = getc(file)) != '\n' && ch != '@' && ch != EOF)
+                continue;
+            continue;
+        } else if (ch != '>' && ch != '<' &&
+            ch != '.' && ch != ',' &&
+            ch != '+' && ch != '-' &&
+            ch != ':' && ch != ';' &&
+            ch != '[' && ch != ']' && !isalnum(ch)) {
+            continue;  // 其他内容也被忽略
+        }
+
+        if (index > size) {
+            bf_byte byte = calloc(size + FILE_READ_SIZE + 1, sizeof(bf_byte));
+            strcpy(byte, code->byte);
+            free(code->byte);
+            code->byte = byte;
+        }
+
+        code->byte[index] = (char)ch;
+        index++;
+    }
+
+    return code;
+}
+
+void bf_printBrainFuck(bf_code code) {
+    printf("%s", code->byte);
+}
+
+static bf_item *makeItem() {
+    bf_item *item = calloc(1, sizeof(bf_item));
+    return item;
+}
+
+static void freeItem(bf_item *item) {
+    bf_item *bak;
+    while (item != NULL) {
+        bak = item->next;
+        free(item);
+        item = bak;
+    }
+}
+
+bf_env *bf_setEnv() {
+    bf_env *env = calloc(1, sizeof(bf_env));
+    env->item = makeItem();
+    env->pitem.item = env->item;
+    env->pitem.index = 0;
+    env->pitem.base = env->item;
+    env->error_info = NULL;
+    return env;
+}
+
+void bf_freeEnv(bf_env *env) {
+    freeItem(env->item);
+    free(env);
+}
+
+void bf_initEnv(bf_env *env) {
+    env->pitem.item = env->pitem.base;
+    env->pitem.index = 0;
+    env->error_info = NULL;
+}
+
+static void addItem(bf_item *global) {
+    assert(global != NULL);
+    while (global->next != NULL)
+        global = global->next;
+    global->next = makeItem();
+    global->next->prev = global;
+}
+
+static int runBrainFuck(bf_byte *byte, bf_env *env);
+int bf_runBrainFuck(bf_code code, bf_env *env) {
+    bf_byte byte = code->byte;
+    int status = runBrainFuck(&byte, env);
+
+    if (status != 0)
+        return 1;  // 返回1表示错误
+    else {
+        env->error_info = NULL;
+        return 0;
+    }
+}
+
+static int runBrainFuck_(bf_byte *byte, bf_env *env);
+static int runBrainFuck(bf_byte *byte, bf_env *env) {
+    while (**byte != '\0') {
+        int status = runBrainFuck_(byte, env);
+        if (status != 0)
+            return status;
+    }
+    return 0;
+}
+
+static int runBrainFuck_(bf_byte *byte, bf_env *env) {
+    bf_pitem *pitem = &(env->pitem);
+    switch (**byte) {
+        case '>': {
+            int num = 1;
+            int times = 0;
+            if (isalnum(*(*byte + 1))) {
+                bf_byte new;
+                num = strtol((*byte + 1), &new, 10);
+                *byte = new - 1;
+                times = num / 20;
+                num = num % 20;
+            }
+
+            while (times-- != 0) {
+                if (pitem->item->next == NULL)
+                    addItem(pitem->item);
+                pitem->item = pitem->item->next;
+            }
+
+            pitem->index += num;
+            if (pitem->index >= TABLE_SIZE) {
+                pitem->index = pitem->index - TABLE_SIZE;
+                if (pitem->item->next == NULL)
+                    addItem(pitem->item);
+                pitem->item = pitem->item->next;
+            }
+            break;
+        }
+        case '<': {
+            int num = 1;
+            int times = 0;
+            if (isalnum(*(*byte + 1))) {
+                bf_byte new;
+                num = strtol((*byte + 1), &new, 10);
+                *byte = new - 1;
+                times = num / 20;
+                num = num % 20;
+            }
+
+            while (times-- != 0) {
+                pitem->item = pitem->item->prev;
+                if (pitem->item == NULL) {
+                    pitem->item = makeItem();
+                    pitem->item->next = env->item;
+                    env->item->prev = pitem->item;
+                    env->item = pitem->item;
+                }
+            }
+
+            pitem->index -= num;
+            if (pitem->index < -1) {
+                pitem->index = (TABLE_SIZE + pitem->index);  // 如 pitem->index = -1, 即代表获取最后一个元素, 下标为 TABLE_SIZE - 1
+                pitem->item = pitem->item->prev;
+                if (pitem->item == NULL) {
+                    pitem->item = makeItem();
+                    pitem->item->next = env->item;
+                    env->item->prev = pitem->item;
+                    env->item = pitem->item;
+                }
+            }
+            break;
+        }
+        case '+': {
+            int num = 1;
+            if (isalnum(*(*byte + 1))) {
+                bf_byte new;
+                num = strtol((*byte + 1), &new, 10);
+                *byte = new - 1;
+            }
+            pitem->item->data[pitem->index] += num;
+            break;
+        }
+        case '-':{
+            int num = 1;
+            if (isalnum(*(*byte + 1))) {
+                bf_byte new;
+                num = strtol((*byte + 1), &new, 10);
+                *byte = new - 1;
+            }
+            pitem->item->data[pitem->index] -= num;
+            break;
+        }
+        case ',':  // 输入
+            pitem->item->data[pitem->index] = getc(stdin);
+            if (pitem->item->data[pitem->index] != '\n' && pitem->item->data[pitem->index] != EOF) {
+                int ch;
+                while ((ch = getc(stdin)) != '\n' && ch != EOF)
+                    continue;
+            }
+            break;
+        case '.': {  // 输出
+            int data = pitem->item->data[pitem->index];
+            putc(data, stdout);
+            fflush(stdout);
+            break;
+        }
+        case ';': {  // 输入
+            char num[6];
+            char *end;
+            fgets(num, 6, stdin);
+
+            if (strchr(num, '\n') == NULL) {  // num 中不存在 \n
+                int ch;
+                while ((ch = getc(stdin)) != '\n' && ch != EOF)
+                    continue;
+            }
+
+            pitem->item->data[pitem->index] = strtol(num, &end, 10);
+            if (*end != '\0') {
+                env->error_info = "':' instruction encountered an illegal number";
+                return -1;
+            }
+
+            break;
+        }
+        case ':':  // 输出
+            printf("%d", pitem->item->data[pitem->index]);
+            break;
+        case '?':
+            bf_initEnv(env);
+            break;
+        case '[':
+            while (1) {
+                if (pitem->item->data[pitem->index] == 0) {  // 跳过代码直到遇到对应的]
+                    int count = 1;
+                    while (count > 0) {
+                        (*byte)++;  // 读取下一个指令
+                        if (**byte == '[')
+                            count++;
+                        else if (**byte == ']')
+                            count--;
+                        else if (**byte == '\0') {
+                            env->error_info = "The ‘]’ was not encountered";
+                            return -1;
+                        }
+                    }
+                    break;  // 跳出最顶层循环 while (1)
+                } else {  // 执行代码
+                    int status;
+                    bf_byte new = *byte + 1;  // 备份 获取下一个指令集
+                    status = runBrainFuck(&new, env);  // 运行, 直到遇到]
+                    if (status != 1) { // 既未遇到 ]
+                        env->error_info = "The ']' was not encountered";
+                        return -1;
+                    }
+                    env->error_info = NULL;  // 清除错误信息 "Illegal ']' encountered"
+                }
+            }
+            break;
+        case ']':
+            (*byte)++;
+            env->error_info = "Illegal ']' encountered";
+            return 1;
+        default:
+            env->error_info = "unsupported command";
+            return -1;
+    }
+
+    (*byte)++;  // 读取下一个指令
+    return 0;
+}
+
+void bf_printError(char *info, bf_env *env) {
+    if (env->error_info != NULL)
+        printf("%s : %s\n", info, env->error_info);
+}