c语言是如何解析表达式语句"2+3*4;"的?
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;"的?的更多相关文章
- 李洪强漫谈iOS开发[C语言-037]-if else 语句
李洪强漫谈iOS开发[C语言-037]-if else 语句
- C语言中嵌入式SQL语句
原文:[转载]C语言中嵌入式SQL语句 http://blog.csdn.net/cnlht/archive/2007/12/12/1930960.aspx原文地址 实验内容: 掌握SQL Serve ...
- C语言可以在执行语句中间定义变量吗?
C语言可以在执行语句中间定义变量吗? 例如:for(int i=0; i<5; i++){ ...
- 【C语言】07-基本语句和运算
一.基本语句 C语言的基本语句跟Java中的差不多,所以,这里只是简单地提一下 循环语句(do while.while.for) 条件语句(if .if-else.switch) goto语句 二.基 ...
- 在C语言中使用scanf语句时遇到的问题总结
在使用visual studio2013编写c语言代码时,遇到了这样的几个小问题,进行如下的总结. 1, 关于使用scanf语句报错的解决方案1 #include <stdio.h> in ...
- c语言(3)--运算符&表达式&语句
计算机的本职工作是进行一系列的运算,C语言为不同的运算提供了不同的运算符! 1.那些运算符们 .基本运算符 算术运算符:+ - * / % ++ -- 赋值运算符:= 逗号运算符:, 关系运算符:& ...
- 在c语言中嵌入汇编语句,对于我来说相当难。
今天早上在csdn论坛上看到一个帖子http://topic.csdn.net/u/20120917/14/82f42e17-977a-4824-95bd-7b79db15d283.html:“C语言 ...
- C语言禁术——goto语句
goto语句是一种无条件转移语句,goto 语句的使用格式为: goto 语句标号;其中标号是一个有效的标识符,这个标识符加上一个“:”(冒号)一起出现在函数内某处,执行goto语句后,程序 ...
- C语言中的循环语句练习
注:练习题目均出自<明解C语言 入门篇> 一.do语句 1,求多个整数的和及平均值 #include<stdio.h> int main(void) { ; //和 ; //整 ...
随机推荐
- Java课堂测试1第三阶段
package sizeyunsuan;//import java.util.Scanner;//import java.util.Random;import java.util.*; public ...
- 题解 [APIO2013]道路费用
link Description 幸福国度可以用 N 个城镇(用 1 到 N 编号)构成的集合来描述,这些城镇 最开始由 M 条双向道路(用 1 到 M 编号)连接.城镇 1 是中央城镇.保证一个 人 ...
- 巧用 CSS3 filter(滤镜) 属性
原文链接:CSS3 filter(滤镜) 属性 效果预览 filter: grayscale(100%); 定义和使用 filter 属性定义了元素(通常是<img>)的可视效果(例如:模 ...
- SLAM名词介绍
gauge freedom:测量自由度 degrees-of-freedom(DoF) 自由度 wide-baseline matches:宽基线匹配 宽基线匹配:从描绘同一场景的两个或多个图像中建立 ...
- 改善深层神经网络-week1编程题(Initializaion)
Initialization 如何选择初始化方式,不同的初始化会导致不同的结果 好的初始化方式: 加速梯度下降的收敛(Speed up the convergence of gradient desc ...
- UltraSoft - Beta - 发布声明
1. Beta版本更新内容 新功能 (1)消息中心页面 课程爬取到新DDL.资源时会以通知的方式通知用户,本次同步更新了哪些内容一目了然.此外,当被作为参与成员添加DDL时也会通知.一些系统通知也会放 ...
- [BUAA]起点 软工第一次作业-热身
项目 内容 这个作业属于哪个课程 2020计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 第一次作业-热身! 我在这个课程的目标是 了解软件开发,提高自己的工程能力和团队协作能力 这个作业在哪 ...
- elasticsearch的索引重建
我们知道es在字段的mapping建立后就不可再次修改mapping的值.在我们实际的情况下有些时候就是需要修改mapping的值,解决方案就是重新构建索引数据. 方式一 : 使用索引别名,创建另外一 ...
- 零基础入门该如何实现C 语言面向对象编程(很有帮助)
零基础如果更快更好的入门C语言,如何在枯燥的学习中找到属于自己的兴趣,如果把学习当成一种事务性的那以后的学习将会很难有更深入的进步,如果带着乐趣来完成学习那将越学越有意思这样才会让你有想要更深入学习的 ...
- 21.6.17 test
\(NOI\) 模拟赛. \(T1\) 正解树形DP,由于不是很熟悉概率和期望所以打了个20pts暴力,说不定见多了概率能打出60pts半正解?最后的虚树更不会. \(T2\) 又是概率,还有坐标数量 ...