c語言是如何處理函式呼叫的?

2022-09-08 22:15:26 字數 3050 閱讀 8446

1.  要編譯的測試**:

int plus(int x, int

y) int main(void

)

2. main中return語句語法分析

if (equal(tok, "

return

"))

2.1 當前token為return,則建立型別為nd_return的node。

2.2 由於return後面跟著plus(3, 4),所以呼叫expr函式解析這個表示式。

2.3 跳過";"符號。

2.4 將型別為nd_return的node的左表示式設定為型別為nd_cast的node。

3. expr的處理

3.1 解析"plus"

if (tok->kind ==tk_ident)

static node *new_var_node(obj *var, token *tok)

當token型別為tk_ident時,從符號表中找到代表plus函式的node,這個node

是在解析plus函式時建立的,就不詳細分析了。

建立新的型別為nd_var的node,這個node的var域為代表plus函式的node。

if (equal(tok, "("

))

if (ty->kind != ty_struct && ty->kind !=ty_union)

exp = new_cast(exp, current_fn->ty->return_ty);

node->lhs =exp;

return node;

解析完函式名plus後,繼續解析函式引數呼叫,如果plus後面跟著是"(",則判斷為函式呼叫,

於是呼叫funcall函式建立型別為nd_funcall的node,funcall函式的引數node即為上面建立的

型別為nd_var的node。

建立完型別為nd_funcall的node,又呼叫new_cast建立型別為nd_cast的節點,這個節點

的左表示式為型別為nd_funcall的node。return的node型別為nd_return,它的左表示式為

nd_cast的node。

3.2 funcall函式

node head ={};

node *cur = &head;

while (!equal(tok, ")"

))

else

if (arg->ty->kind ==ty_float)

cur = cur->next =arg;

}*rest = skip(tok, ")"

);node *node =new_unary(nd_funcall, fn, tok);

node->func_ty =ty;

node->ty = ty->return_ty;

node->args =head.next;

return node;

在funcall函式中呼叫assign函式解析"(3,4)",3被解析為型別為nd_num的node,

node *new_cast(node *expr, type *ty)

呼叫new_cast函式,建立型別為nd_cast的node節點,這個節點的左表示式為代表3的node。

跳過",",繼續呼叫assign解析4,4也被解析為nd_num的node,繼續呼叫new_cast,建立型別為

nd_cast的node節點,這個節點的左表示式為代表4的node。

跳出迴圈,跳過")"。

new_unary函式中建立型別為nd_funcall的node,這個node的左表示式為plus函式的node,

args引數為解析"(3,4)"生成的兩個型別為nd_cast的node。

4. 生成組合語言

static

void gen_stmt(node *node)

println("  jmp .l.return.%s", current_fn->name);

...}

判斷node節點為nd_return,則呼叫gen_expr處理型別為nd_cast的節點。

static

void gen_expr(node *node)

case

nd_var:

gen_addr(node);

return;

case

nd_cast:

gen_expr(node->lhs);

cast(node->lhs->ty, node->ty);

return

;...

}...

4.1 判斷為nd_cast型別的node,則呼叫gen_expr,引數為型別為nd_funcall的node。

4.2 呼叫push_args函式依次生成彙編語句

"mov     rax, 4"

"push    rax"

"mov     rax, 3"

"push    rax"

將4和3壓入棧。

4.3 遞迴呼叫gen_expr,引數為型別為nd_var的node。

4.4 呼叫gen_addr函式生成彙編**"lea     rax, plus",將plus函式位址載入rax暫存器。

4.5 pop語句生成彙編**"pop     rdi","pop     rsi",將3彈入rdi暫存器,將4彈入rsi暫存器,

plus函式中從這兩個暫存器中讀取引數。

4.6 生成彙編**

"mov     r10, rax"

"call    r10"

"add     rsp, 0"

將plus函式位址從rax載入r10暫存器,call語句完成呼叫plus函式,由於沒有分配棧空間傳遞引數

,所以這裡不需要修改rsp暫存器的值。

4.7 "jmp .l.return.main",跳轉到main函式的結尾處,實現return功能。

Silverlight 呼叫 WCF 如何處理錯誤

silverilght 客戶端不支援 faultexception.只會顯示乙個 404 錯誤。所以,服務端丟擲的異常,在客戶端是無法直接通過序列化 反序列化傳遞得到的。但是可以改用下列一些方法來幫助從客戶端得到錯誤資訊 1.在 service 端,將返回值物件重新設計,在其中新增錯誤資訊的字段,傳...

C 如何處理內聯虛函式

當乙個函式是內聯和虛函式時,會發生 替換或使用虛表呼叫嗎?為了弄清楚內聯和虛函式,讓我們將它們分開來考慮。通常,乙個內聯函式是被展開的。01.classcfoo 10.11.intsetval intv 12.13.這裡,如果使用下列 1.cfoo x 2.3.x.setval 17 4.5.int...

Tomcat Server是如何處理http請求的

下面就讓我們簡單了解一下 tomcat server處理乙個http請求的過程 假設來自客戶的請求為 jsp1 請求被傳送到本機埠8080,被在那裡偵聽的coyote http 1.1 connector獲得 2 connector把該請求交給它所在的service的engine來處理,並等待來自e...