1. 程式人生 > >C指標原理(41)-遞迴(2)

C指標原理(41)-遞迴(2)

編譯:

[email protected]:~ % gcc bfi.c -o bfi

bfi.c: In function 'interpret':

bfi.c:35: warning: incompatible implicit declaration of built-in function 'exit'

bfi.c:40: warning: incompatible implicit declaration of built-in function 'exit'

[email protected]:~ % 

下面的hello.b輸出經典的hello,world:

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

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

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

用剛生成的bf語言直譯器執行它:

[email protected]:~ % ./bfi hello.b

Hello World!

prime.b完成指定整數內質數的計算:

===================================================================

======================== OUTPUT STRING ============================

===================================================================

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

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

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

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

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

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

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

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

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

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

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

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

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

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

===================================================================

======================== INPUT NUMBER  ============================

===================================================================

+                          cont=1

[

 -                         cont=0

 >,

 ======SUB10======

 ----------

 [                         not 10

  <+>                      cont=1

  =====SUB38======

  ----------

  ----------

  ----------

  --------

  >

  =====MUL10=======

  [>+>+<<-]>>[<<+>>-]<     dup

  >>>+++++++++

  [

   <<<

   [>+>+<<-]>>[<<+>>-]<    dup

   [<<+>>-]

   >>-

  ]

  <<<[-]<

  ======RMOVE1======

  <

  [>+<-]

 ]

 <

]

>[<<+>>-]<<

===================================================================

======================= PROCESS NUMBER  ===========================

===================================================================

==== ==== ==== ====

numd numu teid teiu

==== ==== ==== ====

+<-

[

 >+

 ======DUP======

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

 >+<--

 >>>>>>>>+<<<<<<<<   isprime=1

 [

  >+

  <-

  =====DUP3=====

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

  =====DUP2=====

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

  >>>

  ====DIVIDES=======

  [>+>+<<-]>>[<<+>>-]<   DUP i=div

  

  <<

  [

    >>>>>+               bool=1

    <<<

    [>+>+<<-]>>[<<+>>-]< DUP

    [>>[-]<<-]           IF i THEN bool=0

    >>

    [                    IF i=0

      <<<<

      [>+>+<<-]>>[<<+>>-]< i=div

      >>>

      -                  bool=0

    ]

    <<<

    -                    DEC i

    <<

    -

  ]

  

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

  >[-]<                  CLR div

  =====END DIVIDES====

  [>>>>>>[-]<<<<<<-]     if divides then isprime=0

  <<

  >>[-]>[-]<<<

 ]

 >>>>>>>>

 [

  -

  <<<<<<<[-]<<

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

  >>

  ===================================================================

  ======================== OUTPUT NUMBER  ===========================

  ===================================================================

  [>+<-]>

  [

   ======DUP======

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

  

  

   ======MOD10====

   >+++++++++<

   [

    >>>+<<              bool= 1

    [>+>[-]<<-]         bool= ten==0

    >[<+>-]             ten = tmp

    >[<<++++++++++>>-]  if ten=0 ten=10

    <<-                 dec ten     

    <-                  dec num

   ]

   +++++++++            num=9

   >[<->-]<             dec num by ten

  

   =======RROT======

      [>+<-]

   <  [>+<-]

   <  [>+<-]

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

   <

  

   =======DIV10========

   >+++++++++<

   [

    >>>+<<                bool= 1

    [>+>[-]<<-]           bool= ten==0

    >[<+>-]               ten = tmp

    >[<<++++++++++>>>+<-] if ten=0 ten=10  inc div

    <<-                   dec ten     

    <-                    dec num

   ]

   >>>>[<<<<+>>>>-]<<<<   copy div to num

   >[-]<                  clear ten

  

   =======INC1=========

   <+>

  ]

  

  <

  [

   =======MOVER=========

   [>+<-]

  

   =======ADD48========

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

  

   =======PUTC=======

   <.[-]>

  

   ======MOVEL2========

   >[<<+>>-]<

  

   <-

  ]

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

  ===================================================================

  =========================== END FOR ===============================

  ===================================================================

  >>>>>>>

 ]

 <<<<<<<<

 >[-]<

  [-]

 <<-

]

======LF========

++++++++++.[-]

用剛編譯生成的bf語言直譯器執行它:

[email protected]:~ % ./bfi prime.b

Primes up to: 20

2 3 5 7 11 13 17 19 

BF直譯器分析:

1、main函式以只讀方式開啟BF語言的原始碼檔案,然後,將BF原始檔按位元組逐個拷入陣列f中,並在最後加上字串的結束標誌0,最後,以陣列f為引數,呼叫interpret函式解釋執行BF語言原始碼。

if((z=fopen(argv[1],"r"))) {

while( (b=getc(z))>0 )

*s++=b;

*s=0;

interpret(f);

}

2、BF語言的直譯器以陣列為資料中心進行計算,在它的計算模型中,需要一個指向陣列的指標,通過這個指標的移動以及對指標指向內容的操作完成所有的計算。因此,程式在開頭處聲明瞭直譯器的核心:陣列a與f,資料a存放BF指令所操作的資料,陣列f存放BF語言程式碼檔案,同時宣告指標變數s指向f陣列的第一個元素。

char a[5000], f[5000], b, o, *s=f;

3、interpret函式解析

這個函式是實現BF語言解釋執行的關鍵。interpret函式接受陣列指標c(指存放向BF語言原始碼的陣列),然後通過while語句逐個字元提取BF原始碼(因為BF原始碼中每個字元就是一條指令),通過swith...case...語句塊判斷BF指令(<、>、+、-、.、,、[、]),執行BF指令。

這些指令分為非跳轉指令與跳轉指令:

(1)非跳轉指令完成了除迴圈外的其它功能。比如移動指標(指標指變數p,比如程式碼中的“ p--”以及“p++”)、對陣列(陣列指變數a,比如程式碼中的“a[p]++”以及“a[p]--”)的操作、輸出(程式碼中的“putchar(a[p]); fflush(stdout); break;”)和輸入(程式碼中的“case ','”標示的語句塊)。

void interpret(char *c)

{

char *d; int tmp;

r++;

while( *c ) {

      //if(strchr("<>+-,.[]\n",c))printf("%c",c);

      switch(o=1,*c++) {

      case '<': p--;        break;

      case '>': p++;        break;

      case '+': a[p]++;     break;

      case '-': a[p]--;     break;

      case '.': putchar(a[p]); fflush(stdout); break;

      case ',': 

    tmp=getchar();

    if (tmp == EOF) a[p]=0; 

    else a[p]=tmp;

................

        .................

}

r--;

}

(2)跳轉指令完成了迴圈功能。在迴圈指令的解釋執行過程中,使用了遞迴機制完成了BF語言的“[”與”]” 指令的解釋,“[”標示著一段迴圈的開始,而“]”標示著一段迴圈的結束,這意味著迴圈可以巢狀,可以由多個“[”與”]” 指令組成多層迴圈。

[

如果指標指向的單元值為零,向後跳轉到對應的]指令的次一指令處

]

如果指標指向的單元值不為零,向前跳轉到對應的[指令的次一指令處

因為可能存在多種迴圈,所以必須找到本次迴圈開始的“[”對應的“]”處,迴圈的條件通過指標指向的單元值來決定,只要指標指向的內容為0,則迴圈結束,否則迴圈繼續。

通過下面這段語句,完成對應“[”的“]”的查詢,尋找的過程中,更新下一步要執行的BF指令指標(for迴圈語句中的“c++”):

for( b=1,d=c; b && *c; c++ )

b+=c=='[', b-=c==']';

找到迴圈的結束處後,對指標指向的單元值( 下面程式碼中的“a[p]”)進行判斷,只要單元值不為0,則遞迴呼叫interpret函式進行下一條指令的解釋:

while( a[p] )

interpret(d);

為防止迴圈的符號不對應,比如說,最後多了迴圈結束標誌”]”,則出現了異常,程式非正常退出,如下面程式碼所示:

case ']':

puts("UNBALANCED BRACKETS"), exit(0);   

對這2個指令的解釋的全部程式碼如下:

void interpret(char *c)

{

char *d; int tmp;

r++;

while( *c ) {

      ............

          case '[':

for( b=1,d=c; b && *c; c++ )

b+=c=='[', b-=c==']';

if(!b) {

c[-1]=0;

while( a[p] )

interpret(d);

c[-1]=']';

break;

}

case ']':

puts("UNBALANCED BRACKETS"), exit(0);   

              .................................