我用C. 这里托管的最新版本写了一个小型的Brainfuck翻译。
我发现很难测试我的解释器,因为用Brainfuck编写一个程序有点困难(或者至少非常乏味),而且我在网上找到的许多片段要么没有输出,要么非常神秘,所以我不知道是否一切正常。
不过,我已经在上面测试了一些程序,我测试的程序也很有效。
任何批评/建议都会很好。
#include <stdio.h>
#define MEMSIZE 30000
int memory[MEMSIZE];
int instructions[MEMSIZE];
int memptr = 0;
int insptr = 0;
int isInstruction(char);
void runInstruction(char);
int main(int argc, char *argv[]) {
// Open input file
FILE *file = fopen(argv[1], "r");
if (file == 0){
printf("Error: Could not open source file\n");
return 0;
}
// Read all instructions from input
char c;
int i = 0;
int balance = 0; // Keeps track of `[` and `]` balance
while ((c = fgetc(file)) != EOF && i < MEMSIZE){
if(isInstruction(c)){
instructions[i] = c;
i++;
if (c == '[')
balance++;
if (c == ']')
balance--;
}
}
// Close input file
fclose(file);
// Error if amount of instructions is more than permitted
if (c != EOF && i >= MEMSIZE){
printf("Error: cannot read more than 30000 instructions\n");
return 0;
}
// Error if `[` and `]` aren't balanced
if (balance != 0){
printf("Error: `[` and `]` were not balanced\n");
return 0;
}
// Run the program
while(insptr < MEMSIZE && instructions[insptr] != 0){
runInstruction(instructions[insptr]);
insptr++;
}
}
int isInstruction(char c) {
if(c == '+' || c == '-' || c == '>' || c == '<' || c == '[' || c == ']' ||
c == '.' || c == ','){
return 1;
} else {
return 0;
}
}
void runInstruction(char c) {
switch(c){
case '+':
memory[memptr]++;
break;
case '-':
memory[memptr]--;
break;
case '>':
if (memptr < MEMSIZE - 1)
memptr++;
else
memptr = 0;
break;
case '<':
if (memptr > 0)
memptr--;
else
memptr = MEMSIZE - 1;
break;
case '[':
if (memory[memptr] == 0)
// seek `]` forward
while(instructions[insptr] != ']'){
insptr++;
}
break;
case ']':
if (memory[memptr] != 0)
// seek `[` backward
while(instructions[insptr] != '['){
insptr--;
}
break;
case '.':
putchar(memory[memptr]);
break;
case ',':
memory[memptr] = getchar();
break;
default:
printf("Error: Encountered unknown instruction `%c`\n",c);
}
}发布于 2016-07-11 09:50:15
您的程序不适用于嵌套循环。如果你有
+ jump into the loop
[ this is the first loop
[ this is the second loop (1)
- decrease current value to get out of loop
]
+ we increment our current value to get back to the start
] whoops, we go to (1)您需要记住遇到的[的位置。一堆东西会派上用场。
此外,余额计算不正确。程序][被解析,因为balance == 0,但它不应该。
如果要打印错误,请使用fprintf(stderr,…)而不是printf。
else显示独占分支
如果两个if彼此独占,请确保使用else if:
if (c == '[')
balance++;
else if (c == ']')
balance--;
// add the balance check, see bugs above
if (balance < 0){
...
}如果可能的话,
接下来,尽可能避免全局变量。这将帮助您测试您的功能。例如,如果将Brainfuck数据分组到一个结构中,则可以检查它是否正确地解析代码:
typedef struct brainfuck_data {
int * memory;
int * instructions;
size_t memsize;
int memptr;
int insptr;
} bf_data_t;
int brainfuck_data_init(bf_data_t * data, size_t memsize) {
data.memory = calloc(memsize, sizeof(int));
if(!data.memory) {
return -1;
}
data.instructions = calloc(memsize, sizeof(int));
if(!data.instructions) {
free(data.memory);
return -2;
}
data.memsize = memsize;
data.memptr = 0;
data.insptr = 0;
}
// and so on for brainfuck_data_deinit现在,如果您有brainfuck_data_file(bf_data_t * data, FILE * fp)或brainfuck_data_parse(bf_data_t *, const char*),您可以检查解析器是否正确地忽略了非brainfuck令牌:
brainfuck_data_parse(&bf1, "[,.]");
brainfuck_data_parse(&bf2, "a simple echo program: [,.]");
int instructionsDiffer = 0;
for(i = 0; i < bf1.memsize && i < bf2.memsize && …; ++i){
if(bf1.instructions[i] != bf2.instructions[i]) {
instructionsDiffer = 1;
break;
}
if(bf1.instructions[i] == 0)
break;
}非全局状态使得测试程序更加容易。
请注意,上面代码中的神奇数字-1和-2应该记录在某个地方,并替换为define。
#define BF_E_ALLOC_MEMORY -1
#define BF_E_ALLOC_INSTR -2
#define BF_E_OK 0目前,解析是在main中完成的。把它分成它自己的功能。上面给出了一个启示。
目前,您的所有指令都保留为字符。相反,您可以使用enum:
typedef enum {
BF_INC, BF_DEC,
BF_GET, BF_PUT
BF_NEXT, BF_PREV
BF_LOOP_START, BF_LOOP_END
} brainfuck_instruction_t;这样,如果你用
typedef struct brainfuck_data {
brainfuck_instruction_t * instructions;
...
} bf_data_t;你已经知道只有有效的指示,除非有人事先篡改了它们。好的副作用是,您可以将几乎所有类似Brainfuck的语言解析成同一组指令,并仍然运行它们。看这个问与答为灵感。
用非平凡的循环测试程序,将其功能分解为更易于测试的小函数,通过使用enums和更少的全局变量使代码更容易出错。
对于使用循环的程序,请尝试计算n_th Fibonacci数(但是对于小_n,因为BF中的加法需要很长时间)。
https://codereview.stackexchange.com/questions/134489
复制相似问题