Linux C编译器从零开发三

news2024/11/24 9:13:01
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

./tmp

echo $?

247

创作不易,小小的支持一下吧!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1835876.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

苹果电脑下载vite包错

苹果电脑下载vite包错/Users/lili/.npm/_cacache/index-v5/c5/50/b451703d03b3802b9ee6b7ff2b0bde4de7f26830eb52c904d6911c137cf8包错解决方式 解决方式&#xff1a;sudo chown -R 501:20 "/Users/wangxin/.npm"

2024/6/18(RBAC,查询用户权限,细粒度授权,选课,支付宝生成二维码支付,支付结果查询需要内网穿透)

黑马程序员【学成在线项目】,P141 测试沙箱支付宝_黑马学成在线支付宝沙箱-CSDN博客 需要内网穿透

甘特图如何画以及具体实例详解

甘特图如何画以及具体实例详解 甘特图是一种常见的项目管理工具又称为横道图、条状图(Bar chart)。是每一位项目经理和PMO必须掌握的项目管理工具。甘特图通过条状图来显示项目、进度和其他时间相关的系统进展的内在关系随着时间进展的情况。但是多项目经理和PMO虽然考了各种证…

OSPF开销、协议优先级、定时器(华为)

#交换设备 OSPF开销值 如果没有定义OSPF接口的开销值&#xff0c;OSPF会根据该接口的带宽自动计算其开销值。 计算公式&#xff1a; 接口开销 带宽参考值 / 接口带宽 &#xff08;取整数部分&#xff0c;结果小于1时取1&#xff09;通过改变带宽参考值可以间接改变接口的开…

多模态融合算法分析

多模态融合算法分析 多模态论文多模态融合早期融合晚期融合混合融合模型级融合 对比分析早期融合&#xff08;Feature-level Fusion&#xff09;晚期融合&#xff08;Decision-level Fusion&#xff09;混合融合&#xff08;Hybrid Fusion&#xff09;ML-LSTM&#xff08;Multi…

BC153 [NOIP2010]数字统计

数字统计 一.题目描述二.输入描述&#xff1a;三.输出描述&#xff1a;四.数字范围五.题目思路六.代码实现 一.题目描述 请统计某个给定范围[L, R]的所有整数中&#xff0c;数字2出现的次数。 比如给定范围[2, 22]&#xff0c;数字2在数2中出现了1次&#xff0c;在数12中出现1次…

[机器学习算法]线性回归

1. 理解基本概念 在开始学习线性回归之前&#xff0c;确保理解以下基本概念&#xff1a; 自变量&#xff08;特征&#xff09;&#xff1a;用来预测因变量&#xff08;目标&#xff09;的输入变量。 因变量&#xff08;目标&#xff09;&#xff1a;需要预测的输出变量。 回归…

网关助力边缘物联网

网关助力边缘物联网 在探讨网关如何助力边缘物联网&#xff08;IoT&#xff09;的议题时&#xff0c;我们不得不深入分析这一技术交汇点的复杂性与潜力。边缘计算与物联网的融合&#xff0c;通过将数据处理与分析能力推向网络边缘&#xff0c;即数据生成的地方&#xff0c;极大…

自我激励学习提升语言模型的推理能力

随着人工智能技术的快速发展&#xff0c;语言模型&#xff08;LMs&#xff09;在各种下游任务中展现出了卓越的能力。特别是在少样本&#xff08;few-shot&#xff09;和零样本&#xff08;zero-shot&#xff09;学习环境中&#xff0c;通过吸收特定任务的指令和示例&#xff0…

IDEA设置nacos权重

本地开发的时候&#xff0c;连接开发环境的NACOS&#xff0c;有时候会有其他请求发送到自己的机子上&#xff0c;由于本地代码会有更新不及时的情况&#xff0c;导致代码报错&#xff0c;同时也会影响本地的日志输出&#xff0c;此时只要在idea设置 spring.cloud.nacos.discov…

icloud 邮箱登入失败

APP NAME mail2HOSTING APP NAME cloudos2CLIENT TIME Tue Jun 11 2024 09:00:47 GMT0800 (中国标准时间) (1718067647802)USER AGENT Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36HOSTNAME www.icloud.…

掌握这三点软文营销技巧:轻松助力品牌传播

在营销方式层出不穷的今天&#xff0c;软文推广已不再只是简单的文字堆砌&#xff0c;而是成为了品牌与消费者深度沟通的桥梁。随着消费者获取信息的渠道越来越多元化&#xff0c;软文推广也迎来了新的趋势和挑战。今日投媒网将与您分享如何在新时代背景下&#xff0c;提升软文…

空气质量预报模式系统WRF-CMAQ

空气污染问题日益受到各级政府以及社会公众的高度重视&#xff0c;从实时的数据监测公布到空气质量数值预报及预报产品的发布&#xff0c;我国在空气质量监测和预报方面取得了一定进展。随着计算机技术的高速发展、空气污染监测手段的提高和人们对大气物理化学过程认识的深入&a…

已解决:geecg Column ‘id‘ in order clause is ambiguous

报错&#xff1a;Column id in order clause is ambiguous&#xff1b; MyBatis关联查询&#xff0c;相同字段名冲突&#xff0c;sql语句已经使用别名但仍然报错。 分析&#xff1a;写mapper映射文件时&#xff0c;在写到一对一关联&#xff0c;一对多关联时&#xff0c;由于两…

Maven 配置学习:存在两个本地私服如何配置

Maven 配置学习&#xff1a;存在两个本地私服如何配置 目录 Maven 配置学习&#xff1a;存在两个本地私服如何配置解释&#xff1a;1.本地仓库位置&#xff1a;2.Profiles 定义&#xff1a;3.Repositories 定义顺序&#xff1a;4.Active Profiles&#xff1a; 操作步骤&#xf…

掌握rpc、grpc并探究内在本质

文章目录 rpc是什么&#xff1f;又如何实现服务通信&#xff1f;理解rpcRPC的通信过程通信协议的选择小结RPC VS Restful net_rpc实践案例net/rpc包介绍创建服务端创建client 看看net_rpc的通信调度实现的内部原理明确目标基于自己实现的角度分析我会怎么做代码分析 grpc介绍与…

电脑数据恢复,掌握4个方法,恢复数据很简单!

在数字化浪潮席卷全球的今天&#xff0c;电脑数据已成为我们生活与工作中不可或缺的一部分。然而&#xff0c;当这些数据因各种原因意外丢失或损坏时&#xff0c;那种失落与无助的感觉常常令人倍感焦虑。 想象一下&#xff0c;你正在为一项重要项目加班加点&#xff0c;突然电…

PHP基础语法【上】

文章目录 一、环境安装二、代码应该写在哪里&#xff1f;三、什么是错误&#xff1f;四、变量无需声明变量变量命名规则变量的作用域可变变量 五、常量常量的定义常量的特性 六、数据类型NULL 空值Boolean 布尔类型Integer 整型Float 浮点型String 字符串Array 数组Object 对象…

Matlab复数相关

文章目录 MATLAB复数相关知识相关函数 MATLAB复数相关知识 相关函数 假定存在复数zabi 函数说明real(z)返回复数z的实部&#xff08;a&#xff09;imag(z)返回复数z的虚部&#xff08;b&#xff09;abs(z)返回复数的模即|z| &#xff08; ( a 2 ) ( b 2 ) \sqrt{(a^2)(b^2)…

国内docker镜像加速

自己注册一个阿里云或者华为云的账户&#xff0c;搜索镜像 点击开通&#xff0c;再点击镜像加速器&#xff0c;可以看到自己的加速器地址&#xff0c;然后替换就可以了。再去pull即可成功&#xff0c;但是响应还是要慢一点