Linux C编译器从零开发三
AST语法树

BNF抽象
expr = equality
equality = relational ("==" relational | "!=" relational)*
relational = add ("<" add | "<=" add | ">" add | ">=" add)*
add = mul ("+" mul | "-" mul)*
mul = unary ("*" unary | "/" unary)*
unary = ("+" | "-")? primary
primary = num | "(" expr ")"
AST构建
#include "chibicc.h"static Node *expr(Token **rest, Token *tok);
static Node *equality(Token **rest, Token *tok);
static Node *relational(Token **rest, Token *tok);
static Node *add(Token **rest, Token *tok);
static Node *mul(Token **rest, Token *tok);
static Node *unary(Token **rest, Token *tok);
static Node *primary(Token **rest, Token *tok);static Node *new_node(NodeKind kind) {Node *node = calloc(1, sizeof(Node));node->kind = kind;return node;
}static Node *new_binary(NodeKind kind, Node *lhs, Node *rhs) {Node *node = new_node(kind);node->lhs = lhs;node->rhs = rhs;return node;
}static Node *new_unary(NodeKind kind, Node *expr) {Node *node = new_node(kind);node->lhs = expr;return node;
}static Node *new_num(int val) {Node *node = new_node(ND_NUM);node->val = val;return node;
}// expr = equality
static Node *expr(Token **rest, Token *tok) {return equality(rest, tok);
}// equality = relational ("==" relational | "!=" relational)*
static Node *equality(Token **rest, Token *tok) {Node *node = relational(&tok, tok);for (;;) {if (equal(tok, "==")) {node = new_binary(ND_EQ, node, relational(&tok, tok->next));continue;}if (equal(tok, "!=")) {node = new_binary(ND_NE, node, relational(&tok, tok->next));continue;}*rest = tok;return node;}
}// relational = add ("<" add | "<=" add | ">" add | ">=" add)*
static Node *relational(Token **rest, Token *tok) {Node *node = add(&tok, tok);for (;;) {if (equal(tok, "<")) {node = new_binary(ND_LT, node, add(&tok, tok->next));continue;}if (equal(tok, "<=")) {node = new_binary(ND_LE, node, add(&tok, tok->next));continue;}if (equal(tok, ">")) {node = new_binary(ND_LT, add(&tok, tok->next), node);continue;}if (equal(tok, ">=")) {node = new_binary(ND_LE, add(&tok, tok->next), node);continue;}*rest = tok;return node;}
}// add = mul ("+" mul | "-" mul)*
static Node *add(Token **rest, Token *tok) {Node *node = mul(&tok, tok);for (;;) {if (equal(tok, "+")) {node = new_binary(ND_ADD, node, mul(&tok, tok->next));continue;}if (equal(tok, "-")) {node = new_binary(ND_SUB, node, mul(&tok, tok->next));continue;}*rest = tok;return node;}
}// mul = unary ("*" unary | "/" unary)*
static Node *mul(Token **rest, Token *tok) {Node *node = unary(&tok, tok);for (;;) {if (equal(tok, "*")) {node = new_binary(ND_MUL, node, unary(&tok, tok->next));continue;}if (equal(tok, "/")) {node = new_binary(ND_DIV, node, unary(&tok, tok->next));continue;}*rest = tok;return node;}
}// unary = ("+" | "-") unary
// | primary
static Node *unary(Token **rest, Token *tok) {if (equal(tok, "+"))return unary(rest, tok->next);if (equal(tok, "-"))return new_unary(ND_NEG, unary(rest, tok->next));return primary(rest, tok);
}// primary = "(" expr ")" | num
static Node *primary(Token **rest, Token *tok) {if (equal(tok, "(")) {Node *node = expr(&tok, tok->next);*rest = skip(tok, ")");return node;}if (tok->kind == TK_NUM) {Node *node = new_num(tok->val);*rest = tok->next;return node;}error_tok(tok, "expected an expression");
}Node *parse(Token *tok) {Node *node = expr(&tok, tok);if (tok->kind != TK_EOF)error_tok(tok, "extra token");return node;
}
代码生成
#include "chibicc.h"static int depth;static void push(void) {printf(" push %%rax\n");depth++;
}static void pop(char *arg) {printf(" pop %s\n", arg);depth--;
}static void gen_expr(Node *node) {switch (node->kind) {case ND_NUM:printf(" mov $%d, %%rax\n", node->val);return;case ND_NEG:gen_expr(node->lhs);printf(" neg %%rax\n");return;}gen_expr(node->rhs);push();gen_expr(node->lhs);pop("%rdi");switch (node->kind) {case ND_ADD:printf(" add %%rdi, %%rax\n");return;case ND_SUB:printf(" sub %%rdi, %%rax\n");return;case ND_MUL:printf(" imul %%rdi, %%rax\n");return;case ND_DIV:printf(" cqo\n");printf(" idiv %%rdi\n");return;case ND_EQ:case ND_NE:case ND_LT:case ND_LE:printf(" cmp %%rdi, %%rax\n");if (node->kind == ND_EQ)printf(" sete %%al\n");else if (node->kind == ND_NE)printf(" setne %%al\n");else if (node->kind == ND_LT)printf(" setl %%al\n");else if (node->kind == ND_LE)printf(" setle %%al\n");printf(" movzb %%al, %%rax\n");return;}error("invalid expression");
}void codegen(Node *node) {printf(" .globl main\n");printf("main:\n");gen_expr(node);printf(" ret\n");assert(depth == 0);
}
#include "chibicc.h"int main(int argc, char **argv) {if (argc != 2)error("%s: invalid number of arguments", argv[0]);Token *tok = tokenize(argv[1]);Node *node = parse(tok);codegen(node);return 0;
}
./chibicc "1 + -2* 3 -(4+5/6) > tmp.s
cc -o tmp tmp.s./tmpecho $?247
创作不易,小小的支持一下吧!


相关文章:
Linux C编译器从零开发三
AST语法树 BNF抽象 expr equality equality relational ("" relational | "!" relational)* relational add ("<" add | "<" add | ">" add | ">" add)* add mul ("" …...
02-ES6新语法
1. ES6 Proxy与Reflect 1.1 概述 Proxy 与 Reflect 是 ES6 为了操作对象引入的 API 。 Proxy 可以对目标对象的读取、函数调用等操作进行拦截,然后进行操作处理。它不直接操作对象,而是像代理模式,通过对象的代理对象进行操作,…...
Vue3中VueRouter基本用法及与Vue2中路由使用差异解析
Vue Router 在 Vue3 中被重写,使用了 Vue3 的 Composition API。使用上跟Vue2 相比有些不同,需要注意。 首先,让我们来看一下 Vue3 中 VueRouter 的基本使用方法: 安装 Vue Router: npm install vue-routernext创建…...
10.Docker Compose容器编排
文章目录 Compose简介安装和卸载步骤核心概念compose文件两要素 使用步骤Compose常用命令微服务测试本地编码打包编写Dockerfile文件构建镜像 不使用Compose调试使用Compose调试WordPress测试验证增量更新 Compose简介 docker建议我们每一个容器中只运行一个服务,因为docke…...
【算法——动态规划(从dfs回溯开始推导dp)】
基础理论 递归: 递:大问题分解子问题的过程 ; 归:产生答案 dp:只进行归;用已知的最底层的(递归的边界,搜索树的底),推出未知 《视频索引》 一句话&…...
不是所有洗碗机都能空气除菌 友嘉灵晶空气除菌洗碗机评测
精致的三餐让你以为生活是“享受”,可饭后那些油腻的锅碗瓢盆却成了你我美好生活的最大障碍。想要只吃美食不洗碗,那一台优秀的洗碗机就必不可少了!今天,ZOL中关村在线要评测的就是这样一台不光洗得干净更能有效除菌抑菌的洗碗机—…...
【Linux】如何创建yum 组(yum groups)
如何创建yum 组(yum groups) 在 yum 中创建组信息需要手动编辑并创建一个组文件,然后使用 createrepo 工具生成组信息。以下是一个详细的步骤指南: 1. 创建组信息文件 首先,创建一个 XML 文件来定义组信息。例如,创建一个名为 …...
Linux ssh远程关闭如何保持进程在后台运行的解决方案
问题描述: Unix/Linux下一般想让某个程序在后台运行,很多都是使用 nohup & 在程序结尾让程序自动运行。 使用SSH远程Linux服务器启动应用,都是使用nohup &命令,结果关闭SSH应用仍然挂断了。 我们很多程序并不象mysqld一…...
TypeScript中的泛型
在 TypeScript(简称 TS)中,泛型(Generics)是一种允许你为组件(如类、接口和函数)定义灵活、可重用的类型的方式。泛型可以看作是一种类型参数化,允许你在声明时定义一个或多个类型占…...
LeetCode-2779. 数组的最大美丽值【数组 二分查找 排序 滑动窗口】
LeetCode-2779. 数组的最大美丽值【数组 二分查找 排序 滑动窗口】 题目描述:解题思路一:滑动窗口与排序解题思路二:0解题思路三:0 题目描述: 给你一个下标从 0 开始的整数数组 nums 和一个 非负 整数 k 。 在一步操…...
RIP与OSPF发布默认路由(华为)
#交换设备 RIP与OSPF发布默认路由 合理使用默认路由可以很大程度上减少本地路由表的大小,并可以较好的隐藏一个网络中的路由信息,保护自身网络的隐秘性 另外如果在同一个路由器两端使用了不同的路由协议,那么如果不做路由引入或者发布默认…...
Android 一个改善的okHttp封装库
Android Studio 使用前,对于Android Studio的用户,可以选择添加: compile project(‘:okhttputils’) 或者 compile ‘com.zhy:okhttputils:2.0.0’ Eclipse 自行copy源码。 二、基本用法 目前基本的用法格式为: OkHttpUtils .get()…...
瓦罗兰特低价区怎么下载 瓦罗兰特低价区下载教程+免费加速器推荐
瓦罗兰特是由拳头发行的游戏,以其丰富的游戏内容和刺激的竞技体验赢得了广大玩家的喜爱。于其它热门的射击游戏不一样的是,我们在游戏中可以选择不的英雄,每一个英雄都有着自己独特的技能,我们还可以在游戏中强行改变地形帮助我们…...
lspci总结
lspci总结 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿!今天我们将探讨一个在 Linux 系统中常用的命令:lspci。lspci 命令用于列出当前系统中的 P…...
Android开启HTTP服务
需求:通过手机给设备升级固件,设备有WIFI 方案:升级包放到APP可以访问的目录,手机开热点并启动一个HTTP服务,设备连接手机热点,另外,设备端开启一个 telnet 服务,手机通过 telnet 登…...
NLP - word2vec详解
Word2Vec是一种用于将词汇映射到高维向量空间的自然语言处理技术。由Google在2013年提出,它利用浅层神经网络模型来学习词汇的分布式表示。Word2Vec有两种主要模型:CBOW(Continuous Bag of Words)和Skip-gram。 1. 模型介绍 Con…...
AI办公自动化:用通义千问批量翻译长篇英语TXT文档
在deepseek中输入提示词: 你是一个Python编程专家,现在要完成一个编写基于qwen-turbo模型API和dashscope库的程序脚本,具体步骤如下: 打开文件夹:F:\AI自媒体内容\待翻译; 获取里面所有TXT文档ÿ…...
一键解压,无限可能——BetterZip,您的Mac必备神器!
BetterZip for Mac 是一款高效、智能且安全的解压缩软件,专为Mac用户设计。它提供了直观易用的界面,使用户能够轻松应对各种压缩和解压缩需求。 这款软件不仅支持多种压缩格式,如ZIP、RAR、7Z等,还具备快速解压和压缩文件的能力。…...
【数学】什么是最大似然估计?如何求解最大似然估计
背景 最大似然估计(Maximum Likelihood Estimation, MLE)是一种估计统计模型参数的方法。它在众多统计学领域中被广泛使用,比如回归分析、时间序列分析、机器学习和经济学。其核心思想是:给定一个观测数据集,找到一组…...
跟张良均老师学大数据人工智能|企业项目试岗实训开营
我国高校毕业生数量连年快速增长,从2021年的909万人到2022年的1076万人,再到2023年的1158万人,预计到2024年将达到1187万人,2024年高校毕业生数量再创新高。 当年高校毕业生人数不等于进入劳动力市场的高校毕业生人数&#x…...
纯粹直播:革新直播观看体验的一站式跨平台解决方案
纯粹直播:革新直播观看体验的一站式跨平台解决方案 【免费下载链接】pure_live 纯粹直播:哔哩哔哩/虎牙/斗鱼/快手/抖音/网易cc/M38自定义源应有尽有。 项目地址: https://gitcode.com/gh_mirrors/pur/pure_live 您是否曾为在多个直播平台间频繁切换而感到困…...
W3x2Lni深度解析:魔兽地图跨版本转换的架构设计与实现原理
W3x2Lni深度解析:魔兽地图跨版本转换的架构设计与实现原理 【免费下载链接】w3x2lni 魔兽地图格式转换工具 项目地址: https://gitcode.com/gh_mirrors/w3/w3x2lni 魔兽争霸III地图开发面临的最大技术挑战之一就是版本兼容性问题。从1.24.4到1.32.8ÿ…...
告别“金鱼记忆”:Hologres + Mem0,为大模型打造企业级长记忆引擎
想象一下这个场景:一位用户在周一联系某电商平台的智能客服,咨询了一款高端相机的详细参数和优惠活动,并明确表示“我倾向于购买A品牌”。客服助手热情地解答了问题。到了周三,这位用户再次联系客服,想了解这款相机的配…...
国金证券QMT实盘连接指南:手把手教你配置交易环境与策略回测
国金证券QMT实盘连接实战:从环境搭建到策略部署全解析 引言 在量化交易的世界里,工具的选择往往决定了策略执行的效率与稳定性。国金证券QMT作为国内主流的量化交易平台之一,以其稳定的实盘连接能力和丰富的API接口受到众多量化交易者的青睐。…...
【板栗糖GIS】从KML到KMZ:GIS数据压缩、共享与ArcMap实战指南
1. KMZ与KML:GIS数据压缩与共享的黄金拍档 第一次接触KMZ文件时,我也被这个后缀名搞得一头雾水。直到有次野外测绘,队友发来一个带照片的谷歌地图范围文件,才真正体会到它的便利性。简单来说,KMZ就是KML的压缩版本&…...
别再死记硬背了!动态规划解回文问题的填表顺序与状态定义保姆级图解
动态规划解回文问题:从填表顺序到状态定义的思维重塑 第一次接触回文串的动态规划解法时,我盯着那个双重循环的填表顺序发呆了半小时——为什么i要从n-1开始倒着遍历?为什么j又要从i开始正着遍历?更让我困惑的是,dp[i…...
Mermaid CLI 架构解析:企业级图表自动化实战指南
Mermaid CLI 架构解析:企业级图表自动化实战指南 【免费下载链接】mermaid-cli Command line tool for the Mermaid library 项目地址: https://gitcode.com/gh_mirrors/me/mermaid-cli Mermaid CLI 是一个基于 Node.js 和 Puppeteer 的命令行图表生成工具&a…...
CentOS 7 编译 Linux 5.15 内核遇 BTF 报错?别慌,这份保姆级排错指南帮你搞定 dwarves 和 pahole
CentOS 7 编译 Linux 5.15 内核 BTF 报错全攻略:从 dwarves 编译到环境修复 在 CentOS 7 上手动编译较新版本的 Linux 内核(如 5.15 系列)时,启用 BTF(BPF Type Format)功能经常会遇到各种依赖问题。本文将…...
java毕业设计基于springboot+vue的自贡恐龙博物馆门户系统
前言 该系统采用前后端分离 的架构模式,后端使用Spring Boot框架构建,前端则使用Vue.js等框架来构建友好的用户界面。这种架构模式使得开发团队可以独立进行前后端的开发与维护,从而提高开发效率。一、项目介绍 开发语言:Java 框架…...
2026年高性价比个人网盘盘点:告别“空间焦虑”,谁才是真正的效率神器?
在预算有限的情况下寻找个人网盘,大多数人的第一反应是打开计算器,算出“每 GB 只要几分钱”。但作为一个在存储行业摸爬滚打多年的老兵,我要告诉你一个反直觉的事实:对于 90% 的办公族和学生来说,网盘的“空间大小”是…...
