有人能解释一下Brainfuck吗?

4

我正在尝试编写一个brainfuck解释器,但是我似乎缺少一些上下文或其他东西。负责处理"+><>"等转换的函数应该被调用:

std::vector<int> Interpreter::interpret(const std::string &src_,
    const std::vector<int> & input_)

程序测试如下:
    int main()
{
std::vector<int> res;
// output: 1
res = interpret("+.");
for (auto i : res)
std::cout << i << " ";
2
// output: 2
res = interpret(",.", {2});
for (auto i : res)
std::cout << i << " ";
return 0;
}

http://www.muppetlabs.com/~breadbox/bf/

这个链接是关于Brainfuck语言的,它是一种最小化的编程语言,使用指针和移动数据指针来实现计算。通过这种方式,程序员可以使用最少的代码量来实现复杂的操作。 关于视频中的问题,理解可能有困难,但是您可以参考提供的代码和说明,逐步学习并掌握相关知识。另外,30000字节数组的作用是存储编程所需的数据,函数将其转换成对应的Brainfuck命令并执行。希望能对您有所帮助。

Abstract Write a simple interpreter for Brainfk. 1 Introduction

A Brainfk program has an implicit byte pointer, called the pointer, which is free to move around within an array of 30000 bytes, initially all set to zero. The pointer itself is initialized to point to the beginning of this array. The Brainfuck programming language consists of eight commands, each of which is represented as a single character.

> Increment the pointer.
< Decrement the pointer.
+ Increment the byte at the pointer.
- Decrement the byte at the pointer.
. A dot, output the byte at the pointer.
, A comma, 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 example, one version of the "Hello, World!" program in Brainfk is

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

2 Requirement

2.1 Test Program
I will use program to test and grade your code in batch. So please double check your function signature. Failure to run properly may impact your project grade. The entry function will all have the name interpret. And you may implement as many other helper functions as you want. The following sections elaborate on the specifications.

2.1.1 C++ I would use C++11 (g++ -std=c++11 ...) to test your program. So feel free to employ some of the recent goodies added to C++, e.g., lambda function, array initialization, etc. For convenience, please separate your declaration and implementation code in bf.h and bf.cpp. The function signature is std::vector<int> interpret(const std::string &src, const std::vector<int> &input = {});

My test program would look like

int main()  
{  
std::vector<int> res;  
// output: 1  
res = interpret("+.");  
for (auto i : res)  
    std::cout << i << " ";  

// output: 2  
res = interpret(",.", {2});  
for (auto i : res)  
    std::cout << i << " ";  
return 0;  
}  

编辑:目前为止,我所拥有的是:

BFK.h

#pragma once
#include <vector>
#include <iostream>

using namespace std;


char arr[30000];
char* p = arr;

void incPtr();

void decPtr();

void incByte();

void decByte();

void printByte();

void setByte();

void jumpF();

void jumpB();

std::vector<int> interpret(const std::string &src,
    const std::vector<int> & input = {});

BFK.cpp

#include "BFK.h"

void incPtr() {
    p++;
}

void decPtr() {
    p--;
}

void incByte() {
    (*p)++;
}

void decByte() {
    (*p)--;
}

void printByte() {
    std::cout << *p;
}

void setByte() {
    std::cin >> *p;
}

void jumpF() {
    if (*p == 0) {

    }
}

void jumpB() {

}


std::vector<int> interpret(const std::string &src_,
    const std::vector<int> & input_){
    int i = 0;
    int max = src_.size();
    while (i < max) {
        switch (src_[i]) {
        case '>':
            incPtr();
            break;
        case '<':
            decPtr();
            break;
        case '+':
            incByte();
            break;
        case '-':
            decByte();
            break;
        case '.':
            printByte();
            break;
        case ',':
            setByte();
            break;
        case '[':
            jumpF();
            break;
        case ']':
            jumpB();
            break;
        }
    }

    return input_;
}

你应该可以在不实例化任何东西的情况下调用解释器,所以我不知道其他组合方法。我还没有实现跳转功能。


1
并不清楚你写了哪些部分,以及你困惑的是什么。我不知道为什么你选择在运行“interpret”后返回一个新向量。毫无疑问,该向量代表内存(应该是char值,而不是int),对其进行任何更改都会修改原始数据。你需要向我们展示实际输出和预期输出,也许还有你的“interpret”函数。 - paddy
1
展示一下你的 interpret() 函数体。你已经写了些什么了吗? - CinCout
1
@paddy:我认为vector<int>参数是可用输入,因此当,需要读取值时,它来自该向量。类比地,返回的vector<int>.操作的输出。因此测试程序循环返回的向量以打印值。 - Jonathan Leffler
1
这个30,000字节的数组是BF程序的内存;src字符串是BF程序代码,将作用于内存;input向量是输入值的供应;返回的向量是输出值的集合。从规范中我不清楚如果你将当前位置增加到内存中的最后一个字节之后会发生什么,或者在第一个字节之前将其减少,或者尝试在没有值可读取时读取值会发生什么。这些细节可能已经在某个地方详细说明了。 - Jonathan Leffler
你读过维基百科上关于BF的文章吗?如果没有,你应该去看一下。我做了一次谷歌搜索,找到了多个有用的参考资料,但维基百科非常好。除其他事项外,它还讨论了一些BF解释器在指针超出边界时执行的操作变化以及在尝试读取不存在内容时会发生什么。 - Jonathan Leffler
显示剩余7条评论
1个回答

2
如果函数已经接收到一个数组需要翻译,那么30000个字节的数组有何意义?
假设你得到两个数字——2和5——并希望让你的Brainfuck程序打印它们的和。
在所有你能做的就是操作当前单元格中的值和“选择”哪个单元格是当前单元格的情况下,你该怎么办?肯定会有些时候需要一些临时内存。
为了在两个单独的单元格中拥有两个值,以便进行加法运算,您可以这样做:
,>,

如果用户输入 23(十进制,不是 ASCII 码),那么 Brainfuck 程序内存或磁带的前两个字节将如下所示:

[2, 3, 0, 0, ...]
//  ^ This is where our tape pointer is now. We incremented it with `>`

很好,现在该如何进行加法呢?一个解决方案是使用Brainfuck循环。

让我们只通过增加和减少值来相加两个自然数:

int a = 2, b = 3

while (a != 0)
{
    b += 1
    a -= 1
}

基本上,我们将第一个值递减直到它达到零,随着这个值的减少,我们将递增第二个值。随着时间的推移,这将显示:

a = 2, b = 3
a = 1, b = 4
a = 0, b = 5
a == 0, break

因此,使用这种方法,我们确实得到了2 + 3 = 5。在brainfuck中实现这个非常简单。

,  Get value for first cell (a)
>, Get value for second cell (b)
<  Move back to a
[  Loop until a == 0
    >+ Decrement b
    <- Increment a
    We are still at a at this point, so everything is alright
]  Loop again if a != 0
>. Print the final result (sum of a plus b)

所有这些都是为了演示如何使用Brainfuck的带式存储器来完成实际任务。
我相信许多Brainfuck程序将带子视为堆栈。有趣的是,您实际上并不需要了解Brainfuck程序在可用方式中存储临时值的技术。
让我们看看Brainfuck解释器如何逐条指令地处理上述程序。
*表示堆栈中的值是指针现在的位置。
我将某些内容分组,以免过长。
1.,“,”- tape [index] = input(),堆栈现在为[2 *,0,0,...]。 2.,“>” - index + = 1,堆栈现在为[2,0 *,0,...]。 3.,“,”- tape [index] = input(),堆栈现在为[2,3 *,0,...]。 4.,“<”- index-= 1,堆栈现在为[2 *,3,0,...]。 5.,“[”- 如果(tape [index]== 0){skipToLoopEnd(); },不跳转(2 == 0为假),堆栈保持不变 6.,“>+”- 堆栈现在为[2,4 *,0,...]。 7.,“<-”- 堆栈现在为[1 *,4,0,...]。 8.,“]”- 如果(tape [index]!= 0){skipToLoopBegin(); },跳转(1!= 0为真),堆栈保持不变 9.,“>+”- 堆栈现在为[1,5 *,0,...]。 10.,“<-”- 堆栈现在为[0 *,5,0,...]。 11.,“]”- 如果(tape [index]!= 0){skipToLoopBegin(); },不跳转(0!= 0为假),堆栈保持不变 12.,“>” - index + = 1,堆栈现在为[0,5 *,0,...]。 13.,“。”- print(tape [index]),打印5!
不用说,我没有意识到这个问题来自2015年!(耶!)至少将来可能会有人发现这很有用... :^)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接