1

私は難解言語brainf*ck用のコンパイラ/インタプリタを書いています(StackOverflowの冒とく的なポリシーについてはよくわからないので、誰かが私にそうする必要はないと言われるまで自分自身を検閲します)、そして私は走っています非常に不思議な(少なくとも私にとっては)バグに陥り、デバッグ出力の最後の文字が、実行中のbrainf*ckプログラムへの入力として受け入れられます。インタプリタのソースは次のとおりです。brainf*ck.c、プログラムのソース:OR.bf、および実行中のOR.bfからbrainf*ck実行可能ファイルを介した出力の部分的な印刷。(コードが乱雑であることを事前に多くの謝罪。楽しいプロジェクトとして1日以内に通訳を書きました。)助けてくれてありがとう!

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:<* Instruction ptr> <* data ptr>

(SOは上記の行を操作しているように見えるので、brainf * ck.cのeval()の先頭を参照してください。

ご覧のとおり、出力の最後から2番目と最後の行は、getchar()が(何らかの理由で)ユーザー入力を待つのではなく、(何らかの理由で)最後から2番目の行の終わりから改行文字を取得していることを示しています。 1)。

このバグがプログラムに発生した理由は、修正方法よりも興味があります。これは、Cの入力ストリームで思っていたほどのハンドルがないと思われるためですが、修正は(もちろん)大歓迎です。

4

1 に答える 1

2

Cstdinはラインバッファリングされています。これは、から入力を読み取るときにstdin、ユーザーから1行を読み取り(この場合は文字列を入力した"1\n")、要求された分だけ返し、残りをバッファーに格納することを意味します。1文字しか要求しなかったため、を返し、バッファに格納'1'します。'\n'次にキャラクターを要求すると、が返され'\n'ます。

標準Cでは、この動作を防ぐ方法はありません。最良の(普遍的に移植可能な)オプションは、行全体を読み取り、ユーザーが複数の文字を入力しようとした場合に診断を出力し、その行の最初の文字だけを取得することです。そうすれば、次にキャラクターを要求したときに、プロンプトが表示されることが保証されます。\nこれにより、たとえば、ユーザーが改行を取得するために入力するためのサポートを追加したい場合に、解析の余地ができます。必須ではありませんが、いいかもしれません。

ユーザーが行全体を入力するのを待たずに、プログラムで1回のキーストロークを実行して実行を続行する場合は、プラットフォーム固有のライブラリを使用する必要があります。Unixシステム(Linux、OS Xなど)では、おそらく調べる必要ncursesがありますが、それほど重要ではないソリューションがいくつかあります。getchWindowsでは、必要なのは(またはそれgetcheですか?)関数だけだと思います。私は少し前にこの種のことをしました、そしてあなたが望むなら私はおそらくそれを釣り上げることができました、しかしあなたはおそらくそれをオンラインで見つけることができます(私がしたのと同じ方法で)。

于 2011-08-08T18:25:35.553 に答える