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'
下面的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);
.................................