aboutsummaryrefslogtreecommitdiff
path: root/src/parser.c
blob: a235746c94fc0a7c0393c363cd0732093a31dd19 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stdalign.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>

#include "errors.h"
#include "parser.h"

/* #define AST_DFLT_CAP (2048) */
#define AST_DFLT_CAP (8)
#define SIZE_WDTH    (sizeof(size_t) * CHAR_BIT)

static struct ast_soa mk_ast_soa(void);
static void ast_soa_resz(struct ast_soa *);

struct ast_soa
parsetoks(struct lexemes_soa toks)
{
	struct ast_soa ast = mk_ast_soa();

	return ast;
}

struct ast_soa
mk_ast_soa(void)
{
	struct ast_soa soa;

	static_assert(offsetof(struct ast_soa, kinds)
	                  < offsetof(struct ast_soa, lexemes),
	              "KINDS is not the first field before LEXEMES");
	static_assert(offsetof(struct ast_soa, kinds)
	                  < offsetof(struct ast_soa, kids),
	              "KINDS is not the first field before KIDS");
	static_assert(AST_DFLT_CAP * sizeof(*soa.kinds) % alignof(*soa.lexemes)
	                  == 0,
	              "Additional padding is required to properly align LEXEMES");
	static_assert(AST_DFLT_CAP * (sizeof(*soa.kinds) + sizeof(*soa.lexemes))
	                      % alignof(*soa.kids)
	                  == 0,
	              "Additional padding is required to properly align KIDS");

	soa.len = 0;
	soa.cap = AST_DFLT_CAP;

	if ((soa.kinds = malloc(soa.cap * AST_SOA_BLKSZ)) == NULL)
		err("malloc:");
	soa.lexemes = (void *)((char *)soa.kinds + soa.cap * sizeof(*soa.kinds));
	soa.kids = (void *)((char *)soa.lexemes + soa.cap * sizeof(*soa.lexemes));

	return soa;
}

void
ast_soa_resz(struct ast_soa *soa)
{
	static_assert(offsetof(struct ast_soa, kinds)
	                  < offsetof(struct ast_soa, lexemes),
	              "KINDS is not the first field before LEXEMES");
	static_assert(offsetof(struct ast_soa, kinds)
	                  < offsetof(struct ast_soa, kids),
	              "KINDS is not the first field before KIDS");
	static_assert(offsetof(struct ast_soa, lexemes)
	                  < offsetof(struct ast_soa, kids),
	              "LEXEMES is not the second field before KIDS");

	size_t ncap, pad1, pad2, newsz;
	ptrdiff_t lexemes_off, kids_off;

	lexemes_off = (char *)soa->lexemes - (char *)soa->kinds;
	kids_off = (char *)soa->kids - (char *)soa->kinds;

	/* The capacity is always going to be a power of 2, so checking for overflow
	   becomes pretty trivial */
	if ((soa->cap >> (SIZE_WDTH - 1)) != 0) {
		errno = EOVERFLOW;
		err("ast_soa_resz:");
	}
	ncap = soa->cap << 1;

	/* Ensure that soa->lexemes is properly aligned */
	pad1 = alignof(*soa->lexemes)
	     - ncap * sizeof(*soa->kinds) % alignof(*soa->lexemes);
	if (pad1 == alignof(*soa->lexemes))
		pad1 = 0;

	pad2 = alignof(*soa->kids)
	     - (ncap * (sizeof(*soa->kinds) + sizeof(*soa->lexemes)) + pad1)
	           % alignof(*soa->kids);
	if (pad2 != alignof(*soa->kids))
		pad2 = 0;

	newsz = ncap * AST_SOA_BLKSZ + pad1 + pad2;

	if ((soa->kinds = realloc(soa->kinds, newsz)) == NULL)
		err("realloc:");

	soa->lexemes = (void *)((char *)soa->kinds + ncap * sizeof(*soa->kinds)
	                        + pad1);
	soa->kids = (void *)((char *)soa->lexemes + ncap * sizeof(*soa->lexemes)
	                     + pad2);

	memmove(soa->kids, (char *)soa->kinds + kids_off,
	        soa->len * sizeof(*soa->kids));
	memmove(soa->lexemes, (char *)soa->kinds + lexemes_off,
	        soa->len * sizeof(*soa->lexemes));

	soa->cap = ncap;
}