Files
zeekay a4debdba80 Read a .zap schema the way every other ZAP language reads it
C had no front end for the schema language at all. The compiler directory
holds a code generator plugin, which is handed a request by another tool
and never sees schema text, so a .zap file could not be read here in
either form -- indentation or braces.

zapgen reads it. Whitespace-significant source is rewritten into the brace
form BEFORE the parser, exactly as the Go reference does it: a near
identity that only adds the two tokens the brace grammar requires where
the indented form leaves them out. A file already in braces comes back
byte for byte, so one grammar reads both styles and neither is a dialect
of the other.

The identifier grammar is not restated. Its Unicode ranges are taken from
Go's own tables by gen/table, so a name this parser accepts is a name the
Go parser accepts, and a Go release that moves Unicode moves both.

The generated header gives each struct a view over the message bytes and
one reader per field at a fixed offset. Reading is in place and total: a
field past the end reads zero, a pointer into the head or out of the
message reads null. zap_view.h is the one place that says so.

Checked against the Go front end on every .zap in the estate plus 55
adversarial cases and 15000 random ones: the brace form each writes is
byte-identical, the layout each reads is field-for-field the same, and
they accept and refuse the same files for the same stated reason. A
message built by the Go runtime reads back through these bindings with
every field equal.
2026-09-15 11:32:12 -07:00

70 lines
1.0 KiB
C

/* SPDX-License-Identifier: BSD-3-Clause-Eco */
#include "arena.h"
#include <stdlib.h>
#include <string.h>
#define CHUNK (64 * 1024)
struct chunk {
struct chunk *next;
size_t len, cap;
char data[];
};
struct arena {
struct chunk *head;
};
struct arena *arena_new(void)
{
return calloc(1, sizeof(struct arena));
}
void arena_free(struct arena *a)
{
struct chunk *c, *next;
if (!a)
return;
for (c = a->head; c; c = next) {
next = c->next;
free(c);
}
free(a);
}
void *arena_get(struct arena *a, size_t n)
{
struct chunk *c;
size_t cap;
void *p;
n = (n + 15) & ~(size_t)15;
if (!a->head || a->head->cap - a->head->len < n) {
cap = n > CHUNK ? n : CHUNK;
c = calloc(1, sizeof(*c) + cap);
if (!c)
return NULL;
c->cap = cap;
c->next = a->head;
a->head = c;
}
c = a->head;
p = c->data + c->len;
c->len += n;
return p;
}
char *arena_str(struct arena *a, const char *s, size_t n)
{
char *p = arena_get(a, n + 1);
if (!p)
return NULL;
memcpy(p, s, n);
p[n] = '\0';
return p;
}