c语言中if语句是怎么变成汇编代码的详解
作者:Just_4_fun
1. 要编译的测试代码:
int a; int b = 3; int main(void) { if (3) a = 4; else b = 5; }
2. 词法分析
词法分析将c源代码解析成一个个的token。
关键的,将if两个字符解析成一个if token,后续语法分析的输入就从两个字符减少为1个token,减小了语法分析的难度。
3. 语法分析
if (equal(tok, "if")) { Node *node = new_node(ND_IF, tok); tok = skip(tok->next, "("); node->cond = expr(&tok, tok); tok = skip(tok, ")"); node->then = stmt(&tok, tok); if (equal(tok, "else")) node->els = stmt(&tok, tok->next); *rest = tok; return node; }
如果当前处理的token是if,则
3.1 创建新的类型为ND_IF的node。
3.2 跳过if后面的"("。
3.3 调用expr函数解析if语句()中的表达式,并将解析结果存储在node->cond。
3.4 跳过“)”。
3.5 调用stmt处理then语句块中的语句,这里是处理"a = 4;",将解析结果存储在node->then。
3.6 如果if语句还有else部分,则调用stmt处理else语句块中的语句,这里是处理"b = 5;",将解析结果存储在node->els。
3.7 node->cond,node->then,node->els都为node节点。
4. 代码生成
switch (node->kind) { case ND_IF: { int c = count(); gen_expr(node->cond); cmp_zero(node->cond->ty); println(" je .L.else.%d", c); gen_stmt(node->then); println(" jmp .L.end.%d", c); println(".L.else.%d:", c); if (node->els) gen_stmt(node->els); println(".L.end.%d:", c); return; } ...
如果当前处理的node节点类型为ND_IF,则
4.1 gen_expr
这个函数处理if语句的条件部分,这里是处理3。判断node节点为NUM,会生成汇编语句"mov rax, 3",将3载入rax寄存器。
4.2 cmp_zero
cmp_zero会生成汇编语句"cmp eax, 0",比较3和0。
4.3 println(" je .L.else.%d", c);
该语句会生成汇编代码" je .L.else.1",当上条比较语句中eax为0时会执行跳转,跳转到else分支运行。这里由于eax为3,所以不跳转。
4.4 gen_stmt(node->then);
这条语句会将then分支中的语句解析为汇编源码,这里是"a = 4;",这条语句是表达式语句,所以会调用gen_expr函数。
4.4.1 gen_expr
"lea rax, a",将a的地址载入rax寄存器中。
"push rax",将rax入栈。
"mov rax, 4",将4载入rax寄存器中。
"pop rdi",将变量a的地址载入rdi寄存器。
"mov [rdi], eax",将4写入变量a。
4.5 println(" jmp .L.end.%d", c);
执行完then分支代码后跳转到下一条语句处执行。
4.6 println(".L.else.%d:", c);
插入一条标签,表示else分支代码的开始,如果if语句条件为0会跳转到这。
4.7 gen_stmt(node->els);
生成else分支代码,处理"b = 5;"。
"lea rax, b",将变量b的地址载入rax寄存器。
"push rax",将rax寄存器入栈。
"mov rax, 5",将5载入rax寄存器。
"pop rdi",将b的地址载入rdi寄存器。
"mov [rdi], eax",将5写入变量b中。
4.8 println(".L.end.%d:", c);
插入一条标签,表示if语句的结束,then分支语句执行完成后跳转到这里。
总结
到此这篇关于c语言中if语句是怎么变成汇编代码的文章就介绍到这了,更多相关c语言if语句变成汇编代码内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!