我正在为深奥的语言brainf * ck编写一个编译器/解释器(我对StackOverflow的亵渎政策不太确定,所以我会审查自己,直到有人告诉我我不需要),而我我遇到了一个非常神秘的(至少对我来说)错误,其中我的调试输出中的最后一个字符被接受为正在运行的brainf * ck程序的输入。以下是解释器的来源:brainf * ck.c,程序的源代码:OR.bf,以及通过brainf * ck可执行文件运行OR.bf的输出的部分打印。 (许多代码都提前道歉。我在不到一天的时间里就把解释器写成了一个有趣的项目。) 在此先感谢您的帮助!
brainf * ck.c:
#include <stdio.h>
#include <string.h>
char* readCmd(int, char* []);
void readProg(FILE*,char[]);
int checkSyntax(char[]);
void init(char*, char[], char[]);
void run(unsigned char**, unsigned char**);
void eval(unsigned char**, unsigned char**);
int main(int argc, char* argv[])
{
unsigned char data[30000] = {0};
unsigned char* dptr = &(data[0]);
unsigned char** dpptr = &dptr;
unsigned char inst[30000] = {0};
unsigned char* iptr = &(inst[0]);
unsigned char** ipptr = &iptr;
char* cmd = readCmd(argc, argv);
FILE* src = fopen(cmd, "r");
if(src != NULL)
{
readProg(src, inst);
if(checkSyntax(inst))
{
run(ipptr, dpptr);
}
else
{
printf("Syntax error. Please fix your code\n");
}
}
else
{
printf("File '%s' not found.\n", cmd);
}
fclose(src);
return 0;
}
char* readCmd(int argc, char** argv)
{
char* cmd = NULL;
if(argc == 2)
{
cmd = argv[1];
}
else
{
cmd = "";
printf("Usage: %s <filename>.bf\n", argv[0]);
}
return cmd;
}
void readProg(FILE* src, char inst[])
{
int i = 0;
while(!feof(src))
{
char c = fgetc(src);
if(c == '<' || c == '>' || c == '+' || c == '-' || c == '.' || c == ',' || c == '[' || c == ']')
{
inst[i] = c;
i++;
}
}
}
int checkSyntax(char inst[])
{
int open = 0;
int i = 0;
for(i = 0; i < strlen(inst); i++)
{
if(inst[i] == '[')
open++;
if(inst[i] == ']')
open--;
}
return !open;
}
void init(char* cmd, char instruct[], char data[])
{
return;
}
void run(unsigned char** ipptr, unsigned char** dpptr)
{
while(**ipptr != 0)
{
eval(ipptr, dpptr);
(*ipptr)++;
}
return;
}
void eval(unsigned char** ipptr, unsigned char** dpptr)
{
//fprintf(log, "eval: %c %i %x %x\n", **ipptr, **dpptr, *ipptr, *dpptr);
printf("eval: %c %i %x %x\n", **ipptr, **dpptr, *ipptr, *dpptr);
getch();
int open = 0;
switch(**ipptr)
{
case '>':
(*dpptr)++;
break;
case '<':
(*dpptr)--;
break;
case '+':
//printf("b: dptr:%x *dptr:%i\n", *dpptr, **dpptr);
(**dpptr)++;
//printf("a: dptr:%x *dptr:%i\n", *dptr, **dpptr);
break;
case '-':
(**dpptr)--;
break;
case '.':
putchar(**dpptr);
break;
case ',':
**dpptr = getchar();
break;
case '[':
if(**dpptr)
{
//(*ipptr)++;
}
else
{
open++;
do {
(*ipptr)++;
if(**ipptr == '[')
open++;
if(**ipptr == ']')
open--;
} while(open);
}
break;
case ']':
if(**dpptr)
{
open = 1;
do {
(*ipptr)--;
if(**ipptr == ']')
open++;
if(**ipptr == '[')
open--;
} while(open);
}
break;
default:
break;
}
return;
}
OR.bf:
,------------------------------------------------>
,------------------------------------------------<
[[-]>>+<<]
>
[[-]>+<]
>
>+<
[[-]>->+++++++++++++++++++++++++++++++++++++++++++++++++<<]>
[[-]>++++++++++++++++++++++++++++++++++++++++++++++++<]>
.
输出:
user@userland ~/brainf*ck
$ brainf*ck.exe OR.bf
eval: , 0 22149c 2289d0
1
eval: - 49 22149d 2289d0
eval: - 48 22149e 2289d0
eval: - 47 22149f 2289d0
eval: - 46 2214a0 2289d0
eval: - 45 2214a1 2289d0
eval: - 44 2214a2 2289d0
eval: - 43 2214a3 2289d0
eval: - 42 2214a4 2289d0
eval: - 41 2214a5 2289d0
eval: - 40 2214a6 2289d0
eval: - 39 2214a7 2289d0
eval: - 38 2214a8 2289d0
eval: - 37 2214a9 2289d0
eval: - 36 2214aa 2289d0
eval: - 35 2214ab 2289d0
eval: - 34 2214ac 2289d0
eval: - 33 2214ad 2289d0
eval: - 32 2214ae 2289d0
eval: - 31 2214af 2289d0
eval: - 30 2214b0 2289d0
eval: - 29 2214b1 2289d0
eval: - 28 2214b2 2289d0
eval: - 27 2214b3 2289d0
eval: - 26 2214b4 2289d0
eval: - 25 2214b5 2289d0
eval: - 24 2214b6 2289d0
eval: - 23 2214b7 2289d0
eval: - 22 2214b8 2289d0
eval: - 21 2214b9 2289d0
eval: - 20 2214ba 2289d0
eval: - 19 2214bb 2289d0
eval: - 18 2214bc 2289d0
eval: - 17 2214bd 2289d0
eval: - 16 2214be 2289d0
eval: - 15 2214bf 2289d0
eval: - 14 2214c0 2289d0
eval: - 13 2214c1 2289d0
eval: - 12 2214c2 2289d0
eval: - 11 2214c3 2289d0
eval: - 10 2214c4 2289d0
eval: - 9 2214c5 2289d0
eval: - 8 2214c6 2289d0
eval: - 7 2214c7 2289d0
eval: - 6 2214c8 2289d0
eval: - 5 2214c9 2289d0
eval: - 4 2214ca 2289d0
eval: - 3 2214cb 2289d0
eval: - 2 2214cc 2289d0
eval: > 1 2214cd 2289d0
eval: , 0 2214ce 2289d1
eval: - 10 2214cf 2289d1
以上输出格式如下: eval:&lt; * instruction ptr&gt; &lt; * data ptr&gt;
(所以似乎是在修改上面一行,所以只需要在brainf * ck.c中引用eval()的开头。
正如您所看到的,输出的倒数第二行和最后一行表明getchar()是(由于某种原因)从第二行到最后一行的结尾获取换行符而不是等待用户输入(因为它)在第1行做了。
我更感兴趣的是为什么我的程序中出现了这个错误,而不是如何解决它,因为它让我觉得我没有像我想象的那样在C中输入流,但是对于修复的建议(当然)是受欢迎的。
答案 0 :(得分:2)
C stdin
是行缓冲的。这意味着当您从stdin
读取输入时,它会从用户读取一行(在这种情况下,您输入了字符串"1\n"
)并返回尽可能多的请求,将其余内容存储在缓冲区。由于您只询问了一个字符,因此返回'1'
并将'\n'
存储在缓冲区中。下次你要求一个角色时,它会返回'\n'
。
在标准C中,无法阻止此行为。最好的(通用便携式)选项是读取整行,如果用户试图输入多个字符,则打印诊断,然后只取该行的第一个字符。这样,下次它要求一个角色时,它将保证会提示你。这也允许你一些解析室,如果你想添加支持,比如用户输入\n
来获取换行符。这没有必要,但它可能很好。
如果您希望程序进行一次击键并继续执行,而不等待用户输入整行,则需要使用特定于平台的库。在Unix系统(Linux,OS X等)上你应该考虑ncurses
,但是有一些不那么重量级的解决方案。在Windows上,我认为您需要的只是getch
(或者是getche
?)函数。我前一段时间做过这种事情,如果你愿意的话,我可能会把它搞砸,但你可以在网上找到它(就像我一样)。