Skip to content

Instantly share code, notes, and snippets.

@rexim
Last active March 19, 2026 03:32
Show Gist options
  • Select an option

  • Save rexim/583aee92d0d1003da8c4a196d753c1bc to your computer and use it in GitHub Desktop.

Select an option

Save rexim/583aee92d0d1003da8c4a196d753c1bc to your computer and use it in GitHub Desktop.
Patches for Chibicc extentions developed on https://www.youtube.com/watch?v=_dVchhnO_KI
From a5648cbc9db69a87f77db5f3a463880d6e8eeb44 Mon Sep 17 00:00:00 2001
From: rexim <reximkut@gmail.com>
Date: Sun, 15 Mar 2026 21:17:18 +0700
Subject: [PATCH 1/2] Autoderef for structs and unions
---
parse.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/parse.c b/parse.c
index 6acaeb8..c83cf3a 100644
--- a/parse.c
+++ b/parse.c
@@ -2768,8 +2768,15 @@ static Member *get_struct_member(Type *ty, Token *tok) {
// This function takes care of anonymous structs.
static Node *struct_ref(Node *node, Token *tok) {
add_type(node);
- if (node->ty->kind != TY_STRUCT && node->ty->kind != TY_UNION)
- error_tok(node->tok, "not a struct nor a union");
+
+ if (node->ty->kind == TY_PTR && (node->ty->base->kind == TY_STRUCT || node->ty->base->kind == TY_UNION)) {
+ node = new_unary(ND_DEREF, node, tok);
+ add_type(node);
+ }
+
+ if (node->ty->kind != TY_STRUCT && node->ty->kind != TY_UNION) {
+ error_tok(node->tok, "not a struct nor a union nor it is a pointer to a struct or a union");
+ }
Type *ty = node->ty;
--
2.52.0
From 7623edb6e02ac2d7c95ac8bf11fb049ff8327372 Mon Sep 17 00:00:00 2001
From: rexim <reximkut@gmail.com>
Date: Sun, 15 Mar 2026 21:20:04 +0700
Subject: [PATCH 2/2] Lambda functions
---
parse.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
tokenize.c | 2 +-
2 files changed, 77 insertions(+), 1 deletion(-)
diff --git a/parse.c b/parse.c
index c83cf3a..fdd2017 100644
--- a/parse.c
+++ b/parse.c
@@ -171,6 +171,15 @@ static void leave_scope(void) {
}
// Find a variable by name.
+static VarScope *find_var_cstr(char *name) {
+ for (Scope *sc = scope; sc; sc = sc->next) {
+ VarScope *sc2 = hashmap_get2(&sc->vars, name, strlen(name));
+ if (sc2)
+ return sc2;
+ }
+ return NULL;
+}
+
static VarScope *find_var(Token *tok) {
for (Scope *sc = scope; sc; sc = sc->next) {
VarScope *sc2 = hashmap_get2(&sc->vars, tok->loc, tok->len);
@@ -2975,6 +2984,9 @@ static Node *generic_selection(Token **rest, Token *tok) {
return ret;
}
+static void create_param_lvars(Type *param);
+static void resolve_goto_labels(void);
+
// primary = "(" "{" stmt+ "}" ")"
// | "(" expr ")"
// | "sizeof" "(" type-name ")"
@@ -3020,6 +3032,70 @@ static Node *primary(Token **rest, Token *tok) {
return new_ulong(ty->size, start);
}
+ if (equal(tok, "lambda")) {
+ tok = tok->next;
+ Type *return_ty = declspec(&tok, tok, NULL);
+ tok = skip(tok, "(");
+ Type *ty = func_params(&tok, tok, return_ty);
+
+ static size_t lambda_count = 0;
+
+ size_t name_len = snprintf(NULL, 0, "lambda.%zu", lambda_count) + 1;
+ char *name = malloc(name_len);
+ snprintf(name, name_len, "lambda.%zu", lambda_count);
+ lambda_count += 1;
+
+ Obj *fn = new_gvar(name, ty);
+ fn->is_function = true;
+ fn->is_definition = true;
+ fn->is_static = true;
+ fn->is_root = true;
+
+ Obj *saved_fn = current_fn;
+ Obj *saved_locals = locals;
+ current_fn = fn;
+ locals = NULL;
+ enter_scope();
+ create_param_lvars(ty->params);
+
+ // A buffer for a struct/union return value is passed
+ // as the hidden first parameter.
+ Type *rty = ty->return_ty;
+ if ((rty->kind == TY_STRUCT || rty->kind == TY_UNION) && rty->size > 16)
+ new_lvar("", pointer_to(rty));
+
+ fn->params = locals;
+
+ if (ty->is_variadic)
+ fn->va_area = new_lvar("__va_area__", array_of(ty_char, 136));
+ fn->alloca_bottom = new_lvar("__alloca_size__", pointer_to(ty_char));
+
+ tok = skip(tok, "{");
+
+ // [https://www.sigbus.info/n1570#6.4.2.2p1] "__func__" is
+ // automatically defined as a local variable containing the
+ // current function name.
+ push_scope("__func__")->var =
+ new_string_literal(fn->name, array_of(ty_char, strlen(fn->name) + 1));
+
+ // [GNU] __FUNCTION__ is yet another name of __func__.
+ push_scope("__FUNCTION__")->var =
+ new_string_literal(fn->name, array_of(ty_char, strlen(fn->name) + 1));
+
+ fn->body = compound_stmt(&tok, tok);
+ fn->locals = locals;
+ leave_scope();
+ resolve_goto_labels();
+
+ current_fn = saved_fn;
+ locals = saved_locals;
+
+ *rest = tok;
+
+ VarScope *sc = find_var_cstr(name);
+ return new_unary(ND_ADDR, new_var_node(sc->var, tok), tok);
+ }
+
if (equal(tok, "sizeof")) {
Node *node = unary(rest, tok->next);
add_type(node);
diff --git a/tokenize.c b/tokenize.c
index 5c49c02..2744c19 100644
--- a/tokenize.c
+++ b/tokenize.c
@@ -160,7 +160,7 @@ static bool is_keyword(Token *tok) {
if (map.capacity == 0) {
static char *kw[] = {
- "return", "if", "else", "for", "while", "int", "sizeof", "char",
+ "return", "if", "else", "for", "while", "int", "sizeof", "char", "lambda",
"struct", "union", "short", "long", "void", "typedef", "_Bool",
"enum", "static", "goto", "break", "continue", "switch", "case",
"default", "extern", "_Alignof", "_Alignas", "do", "signed",
--
2.52.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment