在現代設計的程式裡,很少再用到
goto
語句了。雖然使用
goto
語句是比較高效,但它使程式也會得非常難懂,非常難維護,比較容易出錯,所以很少使用
goto
語句的。
goto
語句為無條件跳轉語句,它的一般形式為:
goto 標號;
在lcc裡的是用下面的**來處理:
#001case goto:
#002 walk(null, 0, 0);
#003 definept(null);
#004 t = gettok();
#005 if (t == id)
#006
#016 use(p, src);
#017 branch(p->u.l.label);
#018 t = gettok();
#019 }
#020 else
#021 error("missing label in goto/n"); expect(';');
#022 break; 第
2行復位所有分配的記憶體。 第
3行定義執行點。 第
4行獲取下乙個記號。 第
5行判斷
goto
語句後面是否標號變數。如果是標號變數,就跳到第
6行到第
19行裡處理。否則就在第
21行裡提示出錯。 第
7行裡查詢標號是否已經定義。 第
9行是當標號還沒有定義時,就把這個標號安裝到符號表裡。這是在第
9行到第
15行裡處理。 第
17行是生成跳轉到標號的**。
下面再來分析標號語句是怎麼樣定義的,如下:
#001case id:
#002 if (getchr() == ':')
#003 第
2行就判斷乙個
id識別符號是否標號變數,如果在乙個
id後面緊跟著乙個冒號,就是表示宣告了乙個標號變數,所以在第
4行裡呼叫函式
stmtlabel
來處理標號。 第
5行是處理標號後面的語句。
下面來分析函式
stmtlabel:
#001static void stmtlabel(void)
#002
#012
#013if (p->defined)
#014 error("redefinition of label `%s' previously defined at %w/n", p->name, &p->src);
#015
#016p->defined = 1;
#017definelab(p->u.l.label);
#018t = gettok();
#019expect(':');
#020} 第
3行是查詢這個標號是否定義。 第
5行判斷這個標號是否定義,如果沒有定義就新增到符號表。 第
7行是儲存到符號表。 第
8行到第
10行都是設定標號的屬性。 第
13行當重複定義標號時,提示出錯。 第
16行設定這個標號已經定義。 第
17行定義乙個標號。 第
18行獲取下乙個記號。 第
19行檢查標號後是否冒號。
這樣就可以處理
goto
語句和標號語句了,到這裡就把所有基本的語句分析完成了。
LCC編譯器的源程式分析 12 13
語法分析是比較複雜的處理,下面再來分析乙個例子,它的 如下 typedef unsigned short wchar t typedef wchar t wint t 第一句語句在lcc裡的處理,前面已經解釋清楚,主要生成wchar t儲存符號表裡,並且記錄這個id的型別屬性。那麼第二句是怎麼樣通過...
LCC編譯器的源程式分析 18 19
lcc編譯器的源程式分析 19 全域性函式的定義 函式定義funcdefn處理裡,已經準備好呼叫引數和引數返回,接著就是呼叫全域性函式宣告來處理。如下面的 132 宣告函式。133 cfunc dclglobal sclass,id,ty,pt 134 上面的 是處理函式全域性定義。現在就去就分析d...
LCC編譯器的源程式分析 20 復合語句
在 c語言裡,有一種語句叫做復合語句。它是由 把一些語句括起來的,如下面的例子 在lcc 裡處理這樣的復合語句的函式是 compound 它在上面函式定義函式 funcdefn 是這樣呼叫的 150labels table null,labels 151stmtlabs table null,lab...