1.  要编译的测试代码:

int main(void)
{
2+3*4;
}

2. 词法分析

  词法分析将字符变成token,其中很重要的是token的类型,如字符2的token类型为TK_NUM,这在后面的语法分析阶段有用。

3. 语法分析

3.1 解析字符"2"

if (tok->kind == TK_NUM) {
Node *node;
if (is_flonum(tok->ty)) {
node = new_node(ND_NUM, tok);
node->fval = tok->fval;
} else {
node = new_num(tok->val, tok);
} node->ty = tok->ty;
*rest = tok->next;
return node;
}

  如果token类型为数字,则解析数字,2不为浮点数,所以执行else分支。

static Node *new_num(int64_t val, Token *tok) {
Node *node = new_node(ND_NUM, tok);
node->val = val;
return node;
}

  创建一个类型为ND_NUM的node节点,这个节点就代表了数字2,数字2存储在node节点的val变量中。

3.2 解析"+"

static Node *add(Token **rest, Token *tok) {
Node *node = mul(&tok, tok); for (;;) {
Token *start = tok; if (equal(tok, "+")) {
node = new_add(node, mul(&tok, tok->next), start);
continue;
} if (equal(tok, "-")) {
node = new_sub(node, mul(&tok, tok->next), start);
continue;
} *rest = tok;
return node;
}
}

  数字2的node节点由mul函数返回,此时tok为"+",所以会调用new_add函数,在这个函数中会创建类型为ND_ADD的node节点,

这个节点的左表达式为代表数字2的node节点,右表达式为代表乘法运算的node节点。

static Node *new_add(Node *lhs, Node *rhs, Token *tok) {
if (is_numeric(lhs->ty) && is_numeric(rhs->ty))
return new_binary(ND_ADD, lhs, rhs, tok);
...
}
static Node *new_binary(NodeKind kind, Node *lhs, Node *rhs, Token *tok) {
Node *node = new_node(kind, tok);
node->lhs = lhs;
node->rhs = rhs;
return node;
}

3.3 解析"*"

static Node *mul(Token **rest, Token *tok) {
Node *node = cast(&tok, tok); for (;;) {
Token *start = tok; if (equal(tok, "*")) {
node = new_binary(ND_MUL, node, cast(&tok, tok->next), start);
continue;
} if (equal(tok, "/")) {
node = new_binary(ND_DIV, node, cast(&tok, tok->next), start);
continue;
} if (equal(tok, "%")) {
node = new_binary(ND_MOD, node, cast(&tok, tok->next), start);
continue;
} *rest = tok;
return node;:
}
}

  mul函数会调用cast函数返回代表数字3的类型同样为ND_NUM的node节点,这点同解析数字2的过程,不再赘述。

  由于tok此时为"*",所以会创建类型为ND_MUL的乘法node节点,这个节点的左表达式为代表数字3的类型为

ND_NUM的node节点,右表达式为cast函数返回的代表数字4的类型为ND_NUM的node节点。

4. 解析上一步生成的语法树生成汇编代码

static void gen_expr(Node *node) {
switch (node->kind) {
case ND_NUM: {
println(" mov $%ld, %%rax", node->val);
return;
...
} gen_expr(node->rhs);
push();
gen_expr(node->lhs);
pop("%rdi"); switch (node->kind) {
case ND_ADD:
println(" add %s, %s", di, ax);
return; case ND_MUL:
println(" imul %s, %s", di, ax);
return;
...
}
...
}
  4.1 gen_expr的参数为类型为ND_ADD的node节点,首先递归调用gen_expr,传入的参数为类型为ND_MUL的node节点,又会递归调用
gen_expr,传入的参数为类型为ND_NUM的代表数字4的node节点,此时会生成汇编语句"mov  rax, 4",将4载入rax寄存器,gen_expr返回。

  4.2 push函数生成"push    rax",将4压入栈。

  4.3 gen_expr的参数为类型为ND_NUM的代表数字3的node节点,会生成"mov     rax, 3",将3载入rax寄存器,gen_expr返回。

  4.4 pop("%rdi")函数将4弹入rdi寄存器。

  4.5 由于node节点类型为ND_MUL,所以生成"imul    eax, edi",计算3*4,结果保存在eax寄存器中,并从gen_expr返回。

  4.6 回到参数为ND_ADD的gen_expr函数中。

  4.7 push函数生成"push    rax",将3*4压入栈。

  4.8 gen_expr参数为类型为ND_NUM的代表数字2的node节点,会生成"mov     rax, 2",将2载入rax寄存器,gen_expr返回。

  4.9 pop("%rdi");函数将3*4弹入rdi寄存器。

  4.10 由于node节点类型为ND_ADD,所以生成"add     eax, edi",计算2+3*4,结果保存在eax寄存器中,并从gen_expr返回。
  
 
 
 
 
 
 

c语言是如何解析表达式语句"2+3*4;"的?的更多相关文章

  1. 李洪强漫谈iOS开发[C语言-037]-if else 语句

    李洪强漫谈iOS开发[C语言-037]-if else 语句

  2. C语言中嵌入式SQL语句

    原文:[转载]C语言中嵌入式SQL语句 http://blog.csdn.net/cnlht/archive/2007/12/12/1930960.aspx原文地址 实验内容: 掌握SQL Serve ...

  3. C语言可以在执行语句中间定义变量吗?

    C语言可以在执行语句中间定义变量吗? 例如:for(int i=0; i<5; i++){                                                     ...

  4. 【C语言】07-基本语句和运算

    一.基本语句 C语言的基本语句跟Java中的差不多,所以,这里只是简单地提一下 循环语句(do while.while.for) 条件语句(if .if-else.switch) goto语句 二.基 ...

  5. 在C语言中使用scanf语句时遇到的问题总结

    在使用visual studio2013编写c语言代码时,遇到了这样的几个小问题,进行如下的总结. 1, 关于使用scanf语句报错的解决方案1 #include <stdio.h> in ...

  6. c语言(3)--运算符&表达式&语句

    计算机的本职工作是进行一系列的运算,C语言为不同的运算提供了不同的运算符! 1.那些运算符们 .基本运算符 算术运算符:+ - * /  % ++ -- 赋值运算符:= 逗号运算符:, 关系运算符:& ...

  7. 在c语言中嵌入汇编语句,对于我来说相当难。

    今天早上在csdn论坛上看到一个帖子http://topic.csdn.net/u/20120917/14/82f42e17-977a-4824-95bd-7b79db15d283.html:“C语言 ...

  8. C语言禁术——goto语句

    goto语句是一种无条件转移语句,goto 语句的使用格式为:     goto  语句标号;其中标号是一个有效的标识符,这个标识符加上一个“:”(冒号)一起出现在函数内某处,执行goto语句后,程序 ...

  9. C语言中的循环语句练习

    注:练习题目均出自<明解C语言 入门篇> 一.do语句 1,求多个整数的和及平均值 #include<stdio.h> int main(void) { ; //和 ; //整 ...

随机推荐

  1. WEB 标准以及 W3C 的理解与认识

    01.  WEB标准 ①  web标准 简单来说可以分为结构.表现和行为. ②  结构:主要是有HTML标签组成(通俗点说,在页面body里面我们写入的标签都是为了页面的结构)   表现:即指css样 ...

  2. Vue3学习(二)之集成Ant Design Vue

    一.集成Ant Design Vue npm install ant-design-vue@2.0.0-rc.3 --save 兼容性 Ant Design Vue 2.x 支持所有的现代浏览器. 如 ...

  3. 2020.10.9--vj个人赛补题

    B - A Tide of Riverscape 题意:给出一组字符串,由'0','1',' . '组成,' . '可以换成 0或1,判断第 i  个和第 i+p 个字符是否可以不相等,如果可以则输出 ...

  4. django 中的hello word 开心,通过申请博客了,,发个随笔庆祝一下~~~~~~~

    django 中的hello word! 准备:[pymsql,pycharm,django3.0.7] >>>终端中:django-admin.py startproject [项 ...

  5. 欧姆龙PLC HostLink协议整理

    欧姆龙PLC HostLink协议整理 1.常用的存储器功能区 CIO: 输入继电器  272 点(17 CH) 0.00-16.15 输出继电器  272 点(17 CH) 100.00-116.1 ...

  6. js 原型链详解

    目录 构造函数和实例 属性Prototype 属性__proto__ 访问原型上的方法 构造函数也有__proto__ 构造函数的原型也有__proto__ Object.prototype这个原型对 ...

  7. SI Macro

    获取 buf 里的 symbol cbuf = BufListCount() msg(cbuf) ibuf = 0 while (ibuf < cbuf) { hbuf = BufListIte ...

  8. cf12D Ball(MAP,排序,贪心思想)

    题意: N位女士一起聚在一个舞厅.每位女士有三个特征值B,I,R.分别代表美貌,智慧,富有. 对于一位女士而言,如果存在一个女士的B,I,R都分别大于她自己的B,I,R.则她自己会自杀. 统计总共有多 ...

  9. hdu 1069 Monkey and Banana(记忆搜)

    题意: N(不超过30)种木块,每种木块有长.宽.高x,y,z. 木块A可以搭在木块B上当且仅当A的底面长和宽都分别小于B的顶面的长与宽,即不能有超出B的部分. 问垒起来的"木块塔" ...

  10. 聊聊@Transactional 的失效场景,有哪些坑?

    先别急着回答,看完再说也不迟嘛.我们都知道在 Spring 项目中,我们可以直接使用注解 @Transactional 来标识一个事务方法.然而,你可能并不知道这个事务是不是按照你想的方式执行.下面我 ...