kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

commit 0e80961769b914c539ffb502ea6be3cb3130fc8c
parent 1b5a72b7bfb642b0a17e7e5cb8236930bd3a6fab
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Tue, 19 May 2026 16:40:17 -0700

Fix parse edge cases

Diffstat:
Mdoc/BUGS.md | 8++++----
Mlang/c/parse/cg_adapter.c | 1-
Mlang/c/parse/parse_expr.c | 2+-
Mlang/c/parse/parse_init.c | 63++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Mlang/c/parse/parse_type.c | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 111 insertions(+), 17 deletions(-)

diff --git a/doc/BUGS.md b/doc/BUGS.md @@ -12,10 +12,10 @@ Format as: - [x] function declarator with an inline function-pointer return type (no typedef): `6_7_6_20_func_returning_funcptr_no_typedef` - [x] static initializer accepts unary `-` on a floating constant: `6_7_9_30_static_init_neg_float` - [x] `#warning` preprocessing directive (non-fatal, parsing continues): `6_10_warning_directive` -- [ ] static initializer accepts a binary constant expression on floating constants (`1.0f/2.2f`): `6_7_9_31_static_init_const_float_expr` -- [ ] conditional operator allows a comma expression in its middle operand (`a ? b, c : d`): `6_5_15_01_conditional_comma_in_middle` -- [ ] subscript accepts a conditional whose constant arm is `0` without treating it as a null pointer: `6_5_2_1_01_subscript_conditional_zero_branch` -- [ ] struct field declarator `RETTY (*(*name)(P))(IP)` (pointer-to-function-returning-function-pointer; sqlite VFS `xDlSym`): `6_7_6_21_field_ptr_to_func_returning_funcptr` +- [x] static initializer accepts a binary constant expression on floating constants (`1.0f/2.2f`): `6_7_9_31_static_init_const_float_expr` +- [x] conditional operator allows a comma expression in its middle operand (`a ? b, c : d`): `6_5_15_01_conditional_comma_in_middle` +- [x] subscript accepts a conditional whose constant arm is `0` without treating it as a null pointer: `6_5_2_1_01_subscript_conditional_zero_branch` +- [x] struct field declarator `RETTY (*(*name)(P))(IP)` (pointer-to-function-returning-function-pointer; sqlite VFS `xDlSym`): `6_7_6_21_field_ptr_to_func_returning_funcptr` Known bugs caught by other harnesses diff --git a/lang/c/parse/cg_adapter.c b/lang/c/parse/cg_adapter.c @@ -396,7 +396,6 @@ void pcg_store(Parser* p) { if (emit) cfree_cg_store(p->cg, pcg_mem(p, mem_ty ? mem_ty : rv_ty)); pcg_drop_type(p); pcg_drop_type(p); - pcg_push_type(p, rv_ty); } void pcg_deref(Parser* p, const Type* pointee) { diff --git a/lang/c/parse/parse_expr.c b/lang/c/parse/parse_expr.c @@ -2942,7 +2942,7 @@ static void parse_ternary(Parser* p) { to_rvalue(p); require_scalar(p, cg_top_type(p->cg), "conditional operator"); cg_branch_false(p->cg, L_else); - parse_assign_expr(p); + parse_expr(p); to_rvalue(p); result_ty = cg_top_type(p->cg); then_null = null_pointer_constant(p, result_ty); diff --git a/lang/c/parse/parse_init.c b/lang/c/parse/parse_init.c @@ -710,26 +710,67 @@ static void encode_binary128_from_double_le(u8 out[16], double value) { encode_uint128_le(out, 16, lo, hi); } +static double parse_static_float_add(Parser* p); + +static double parse_static_float_primary(Parser* p) { + double v; + if (accept_punct(p, '+')) return parse_static_float_primary(p); + if (accept_punct(p, '-')) return -parse_static_float_primary(p); + if (accept_punct(p, '(')) { + v = parse_static_float_add(p); + expect_punct(p, ')', "')' in floating constant expression"); + return v; + } + if (p->cur.kind == TOK_FLT) { + v = parse_float_literal(p, &p->cur); + advance(p); + return v; + } + if (p->cur.kind == TOK_NUM) { + v = (double)parse_int_literal(p, &p->cur); + advance(p); + return v; + } + perr(p, "expected floating constant expression"); + return 0.0; +} + +static double parse_static_float_mul(Parser* p) { + double v = parse_static_float_primary(p); + for (;;) { + if (accept_punct(p, '*')) { + v *= parse_static_float_primary(p); + } else if (accept_punct(p, '/')) { + v /= parse_static_float_primary(p); + } else { + return v; + } + } +} + +static double parse_static_float_add(Parser* p) { + double v = parse_static_float_mul(p); + for (;;) { + if (accept_punct(p, '+')) { + v += parse_static_float_mul(p); + } else if (accept_punct(p, '-')) { + v -= parse_static_float_mul(p); + } else { + return v; + } + } +} + static int try_parse_static_float(Parser* p, u8* dst, u32 size, const Type* ty) { const Type* uty = type_unqual(p->pool, ty); double value; - int neg = 0; if (!uty || (uty->kind != TY_FLOAT && uty->kind != TY_DOUBLE && uty->kind != TY_LDOUBLE)) { return 0; } - if (is_punct(&p->cur, '-') || is_punct(&p->cur, '+')) { - neg = is_punct(&p->cur, '-'); - advance(p); - } - if (p->cur.kind != TOK_FLT && p->cur.kind != TOK_NUM) - perr(p, "expected floating constant expression"); - value = p->cur.kind == TOK_FLT ? parse_float_literal(p, &p->cur) - : (double)parse_int_literal(p, &p->cur); - if (neg) value = -value; - advance(p); + value = parse_static_float_add(p); if (uty->kind == TY_FLOAT && size == 4u) { union { float f; diff --git a/lang/c/parse/parse_type.c b/lang/c/parse/parse_type.c @@ -1380,6 +1380,8 @@ const Type* parse_declarator_full_info(Parser* p, const Type* base, SrcLoc nloc = {0, 0, 0}; u8 nptrs_inner = 0; u16 inner_quals[8]; + u8 nptrs_nested = 0; + u16 nested_quals[8]; int has_inner_parens = 0; DeclSuffix inner_suffs[8]; int n_inner_suffs = 0; @@ -1428,9 +1430,54 @@ const Type* parse_declarator_full_info(Parser* p, const Type* base, name = p->cur.v.ident; nloc = tok_loc(&p->cur); advance(p); + } else if (is_punct(&p->cur, '(')) { + Tok nn = peek1(p); + if (!is_punct(&nn, '*')) { + if (!allow_abstract) perr(p, "expected declarator name"); + goto after_inner_name; + } + advance(p); /* nested '(' */ + while (accept_punct(p, '*')) { + u16 q = 0; + if (nptrs_nested >= 8) perr(p, "too many pointer levels"); + for (;;) { + if (accept_kw(p, KW_CONST)) { + q |= Q_CONST; + continue; + } + if (accept_kw(p, KW_VOLATILE)) { + q |= Q_VOLATILE; + continue; + } + if (accept_kw(p, KW_RESTRICT)) { + q |= Q_RESTRICT; + continue; + } + if (accept_kw(p, KW_ATOMIC)) { + q |= Q_ATOMIC; + continue; + } + if (starts_attr(p)) { + parse_and_discard_attributes(p); + continue; + } + break; + } + nested_quals[nptrs_nested++] = q; + } + if (p->cur.kind == TOK_IDENT && ident_kw(p, p->cur.v.ident) == KW_NONE) { + name = p->cur.v.ident; + nloc = tok_loc(&p->cur); + advance(p); + } else if (!allow_abstract) { + perr(p, "expected declarator name"); + } + if (starts_attr(p)) parse_and_discard_attributes(p); + expect_punct(p, ')', "')' after nested declarator"); } else if (!allow_abstract) { perr(p, "expected declarator name"); } +after_inner_name: if (starts_attr(p)) parse_and_discard_attributes(p); while (n_inner_suffs < 8) { if (!parse_decl_suffix(p, &inner_suffs[n_inner_suffs])) break; @@ -1497,6 +1544,13 @@ const Type* parse_declarator_full_info(Parser* p, const Type* base, base = apply_decl_suffix(p, base, &inner_suffs[i]); } + for (int i = (int)nptrs_nested - 1; i >= 0; --i) { + base = type_ptr(p->pool, base); + if (nested_quals[i]) { + base = type_qualified(p->pool, base, nested_quals[i]); + } + } + if (info_out && base && base->kind == TY_FUNC && final_fn_suff) { info_out->fn_params = final_fn_suff->params; info_out->fn_nparams = final_fn_suff->nparams;