Replace GNU statement expressions ({...}) in common.h with a static
inline function and do...while(0) macros. Expand case range expressions
(case 'a' ... 'z') in tokenizer.c to individual case labels. Replace
empty initializer braces {} with {0} in parser.c. Add a dummy member
to the empty struct in ast.h. Add -pedantic to zig0_cflags in build.zig
to prevent future regressions.
zig0 now compiles with any C11-conforming compiler, not just those
supporting GNU extensions. This enables bootstrapping with MSVC,
cproc, and other strict C11 compilers.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
75 lines
3.7 KiB
C
75 lines
3.7 KiB
C
// common.h — must be included before any system headers.
|
|
#ifndef _ZIG0_COMMON_H__
|
|
#define _ZIG0_COMMON_H__
|
|
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#define SLICE(Type) \
|
|
struct Type##Slice { \
|
|
uint32_t len; \
|
|
uint32_t cap; \
|
|
Type* arr; \
|
|
}
|
|
|
|
static inline void* arr_init_(size_t count, size_t size) {
|
|
void* arr = calloc(count, size);
|
|
if (!arr)
|
|
exit(1);
|
|
return arr;
|
|
}
|
|
|
|
#define ARR_INIT(Type, initial_cap) \
|
|
((Type*)arr_init_((initial_cap), sizeof(Type)))
|
|
|
|
#define SLICE_INIT(Type, initial_cap) \
|
|
{ .len = 0, .cap = (initial_cap), .arr = ARR_INIT(Type, initial_cap) }
|
|
|
|
#define SLICE_RESIZE(Type, slice, new_cap) \
|
|
do { \
|
|
const uint32_t cap_ = (new_cap); \
|
|
Type* new_arr_ = realloc((slice)->arr, cap_ * sizeof(Type)); \
|
|
if (new_arr_ == NULL) { \
|
|
free((slice)->arr); \
|
|
exit(1); \
|
|
} \
|
|
(slice)->arr = new_arr_; \
|
|
(slice)->cap = cap_; \
|
|
} while (0)
|
|
|
|
#define SLICE_ENSURE_CAPACITY(Type, slice, additional) \
|
|
do { \
|
|
if ((slice)->len + (additional) > (slice)->cap) { \
|
|
SLICE_RESIZE(Type, slice, \
|
|
((slice)->cap * 2 > (slice)->len + (additional)) \
|
|
? (slice)->cap * 2 \
|
|
: (slice)->len + (additional)); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define SLICE_APPEND(Type, slice, item) \
|
|
do { \
|
|
SLICE_ENSURE_CAPACITY(Type, slice, 1); \
|
|
(slice)->arr[(slice)->len++] = (item); \
|
|
} while (0)
|
|
|
|
#define ERR_BUF_SIZE 200
|
|
|
|
// SET_ERROR: mark a context as having encountered an error and record a
|
|
// diagnostic message. Both Parser and AstGenCtx carry the same two fields:
|
|
// bool has_compile_errors;
|
|
// char err_buf[ERR_BUF_SIZE];
|
|
#define SET_ERROR(ctx, msg) \
|
|
do { \
|
|
const char* _err_msg = (msg); \
|
|
size_t _err_len = strlen(_err_msg); \
|
|
if (_err_len >= ERR_BUF_SIZE) \
|
|
_err_len = ERR_BUF_SIZE - 1; \
|
|
memcpy((ctx)->err_buf, _err_msg, _err_len); \
|
|
(ctx)->err_buf[_err_len] = '\0'; \
|
|
(ctx)->has_compile_errors = true; \
|
|
} while (0)
|
|
|
|
#endif
|