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.7node->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.1gen_expr

这个函数处理if语句的条件部分,这里是处理3。判断node节点为NUM,会生成汇编语句"mov     rax, 3",将3载入rax寄存器。

4.2cmp_zero

cmp_zero会生成汇编语句"cmp     eax, 0",比较3和0。

4.3println(" je .L.else.%d", c);

该语句会生成汇编代码" je .L.else.1",当上条比较语句中eax为0时会执行跳转,跳转到else分支运行。这里由于eax为3,所以不跳转。

4.4gen_stmt(node->then);

这条语句会将then分支中的语句解析为汇编源码,这里是"a = 4;",这条语句是表达式语句,所以会调用gen_expr函数。

4.4.1gen_expr

"lea     rax, a",将a的地址载入rax寄存器中。

"push rax",将rax入栈。

"mov     rax, 4",将4载入rax寄存器中。

"pop     rdi",将变量a的地址载入rdi寄存器。

"mov     [rdi], eax",将4写入变量a。

4.5println(" jmp .L.end.%d", c);

执行完then分支代码后跳转到下一条语句处执行。

4.6println(".L.else.%d:", c);

插入一条标签,表示else分支代码的开始,如果if语句条件为0会跳转到这。

4.7gen_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.8println(".L.end.%d:", c);

插入一条标签,表示if语句的结束,then分支语句执行完成后跳转到这里。

c语言if语句是如何变成汇编代码的?的更多相关文章

  1. 分析一个C语言程序生成的汇编代码-《Linux内核分析》Week1作业

    署名信息 郭春阳 原创作品转载请注明出处 :<Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1000029000 C源码 这 ...

  2. c语言中函数调用的本质从汇编角度分析

    今天下午写篇博客吧,分析分析c语言中函数调用的本质,首先我们知道c语言中函数的本质就是一段代码,但是给这段代码起了一个名字,这个名字就是他的的这段代码的开始地址 这也是函数名的本质,其实也就是汇编中的 ...

  3. [SQL]SQL语言入门级教材_SQL语言基本语句介绍(四)

    SQL语言基本语句介绍 • 表的建立 关系数据库的主要特点之一就是用表的方式组织数据.表是SQL语言存放数据.查找数据以及更新数据的基本数据结构.在SQL语言中,表有严格的定义,它是一种二维表,对于这 ...

  4. 《Linux内核分析》week1作业-分析一个简单c语言的汇编代码

    1.C语言源码 #include <stdio.h> int g(int x){ ; } int f(int x){ return g(x); } int main(){ )+; } 2. ...

  5. 解析c语言背后的汇编代码

    源码 很简单的c语言代码,作用是交换两个数: #include <stdio.h> void swap(int * a, int * b) { *a = *a + *b - (*b = * ...

  6. Keil 中关于C语言编译生成汇编代码函数名规则

    在keil 中 C语言的函数有带参数和不带参数之分. 一般的资料里说fun(void)类型的函数不带参数,所以,keil编译器生成的汇编的调用地址(函数名) 为fun.这没有错.事实上,不管C语言的函 ...

  7. php入门 数据类型 运算符 语言结构语句 函数 类与面向对象

    php PHP-enabled web pages are treated just like regular HTML pages and you can create and edit them ...

  8. OpenGL ES着色器语言之语句和结构体(官方文档第六章)内建变量(官方文档第七、八章)

    OpenGL ES着色器语言之语句和结构体(官方文档第六章) OpenGL ES着色器语言的程序块基本构成如下: 语句和声明 函数定义 选择(if-else) 迭代(for, while, do-wh ...

  9. 浅析VS2010反汇编 VS 反汇编方法及常用汇编指令介绍 VS2015使用技巧 调试-反汇编 查看C语言代码对应的汇编代码

    浅析VS2010反汇编 2015年07月25日 21:53:11 阅读数:4374 第一篇 1. 如何进行反汇编 在调试的环境下,我们可以很方便地通过反汇编窗口查看程序生成的反汇编信息.如下图所示. ...

随机推荐

  1. 解决VM 与 Device/Credential Guard 不兼容

    通过命令关闭Hyper-V(控制面板关闭Hyper-V起不到决定性作用,要彻底关闭Hyper-V) 以管理员身份运行Windows Powershell (管理员)(Windows键+X) 运行下面命 ...

  2. 告别Vuex,发挥compositionAPI的优势,打造Vue3专用的轻量级状态

    Vuex 的遗憾 Vuex 是基于 Vue2 的 option API 设计的,因为 optionAPI 的一些先天问题,所以导致 Vuex 不得不用各种方式来补救,于是就出现了 getter.mut ...

  3. PublishFolderCleaner 让你的 dotnet 应用发布文件夹更加整洁

    大家都知道,在 dotnet 发布时,将会在输出的 publish 文件夹包含所需的依赖.在 .NET Core 开始,引入了 AppHost 的概念,即使是单个程序集,也需要独立的 Exe 可执行文 ...

  4. 图解Redis6中的9种数据结构,墙裂建议准备去面试的人先看(干货,建议收藏)

    如图所示,Redis中提供了9种不同的数据操作类型,他们分别代表了不同的数据存储结构. 图2-17 数据类型 String类型 String类型是Redis用的较多的一个基本类型,也是最简单的一种类型 ...

  5. javascript-原生-闭包

    1.变量的作用域 前提:这里只全部都通过var创建的变量或对象 1.全局变量:函数外创建变量 var x=10; function test(){ alert("全局变量在test函数中&q ...

  6. vue3.x异步组件

    在大型应用中,我们可能需要将应用分割成小一些的代码块,并且只在需要的时候才从服务器加载一个模块 vue2.x 曾经简单的异步组件 components: { AsyncComponent: () =& ...

  7. Golang通脉之错误处理

    在实际工程项目中,总是通过程序的错误信息快速定位问题,但是又不希望错误处理代码写的冗余而又啰嗦.Go语言没有提供像Java.C#语言中的try...catch异常处理方式,而是通过函数返回值逐层往上抛 ...

  8. 【二食堂】Alpha - Scrum Meeting 10

    Scrum Meeting 10 例会时间:4.20 18:00~18:20 进度情况 组员 昨日进度 今日任务 李健 1. 与柴博合作完成登录注册页面issue 继续完成登录注册页面issue 柴博 ...

  9. 大厂面试题系列:重载(Overload)和重写(Override)的区别。重载的方法能否根据返回类型进行区分

    面试题:重载(Overload)和重写(Override)的区别.重载的方法能否根据返回类型进行区分 面试官考察点猜想 这道题纯粹只是考查基础理论知识,对实际开发工作中没有太多的指导意义,毕竟编辑器都 ...

  10. windows下wchar_t的问题

    使用vs新建工程或者编译工程的时候默认在编译设置里面讲wchar_t设置为内置类型,如下图: 但是在编译相互依赖的工程的时候,如果有的工程不将wchar_t设置为内置类型的时候,将会出现链接错误,需要 ...